Импорт пользователей в батче

Главные вкладки

Аватар пользователя andreyks andreyks 28 октября 2012 в 2:36

Делаю импорт пользователей из другого сайта. Без профайлов только имя, емаил, дату регистрации. По 100 штук. Первая сотня добавляется чуть больше минуты, вторая - чуть медленнее, а потом скорость падает до 13 минут за сотню пользователей. Апач и мускул грузят по 50% на intel i3. 16 тыс я просто не дождусь на рабочем ноуте, а на сервере батч вообще после 4-й сотни зависает.
Делал по John K. VanDyk "Pro Drupal Development". Собственные и контриб модули не отключал, но там хук юсер не использовал.
Мне кажется импорт 16 тыс должен занимать не больше 10 минут. Отрабатывается 160 раз бустрап, 160 раз подключение к внешней базе (с этим проблем нет) и 16000 раз отрабатывает хук юсер. В чём подвох?

И ещё вопрос. Если вставлять напрямик в друпаловскую базу косяки возможны? или лучше продолжать через хуки?

Вот основная (operations) функция:

function custom_migrate_user_import_size($size, &$context) {
  ini_set('max_execution_time', '3000');
  ini_set('memory_limit', '512M');
  error_reporting(E_ALL);
  $connection = custom_migrate_connection();
  if (!is_resource($connection)) {
    file_put_contents('user.log', date('Y-m-d--H:i:s') . "Failed db\n", FILE_APPEND);
    die('Failed db');
  }
 
  // Initialize sandbox the first time through.
  if (!isset($context['sandbox']['progress'])) {
    $context['sandbox']['progress'] = 0;
    $context['sandbox']['page'] = 0;
   
    $query_result = mssql_query("SELECT count(1) AS numrow FROM aspnet_Users u
    INNER JOIN aspnet_Membership m ON m.UserId=u.UserId"
);
    $r = mssql_fetch_assoc($query_result);
    $context['sandbox']['max'] = $r['numrow'];
    mssql_free_result($query_result);
//    file_put_contents('user.log', date('Y-m-d--H:i:s') . " Max: {$context['sandbox']['max']}; Size: {$size} \n", FILE_APPEND);
  }
 
 
   
  $per_page = $size;
  $from = $context['sandbox']['progress'] + 1;//$per_page * $context['sandbox']['page'] + 1;
  $to = $from + $per_page - 1;
 
 
 
  $query_result = mssql_query("SELECT * FROM(
    SELECT  ROW_NUMBER() OVER (ORDER BY m.CreateDate) AS rownum,
    u.UserId, u.UserName, DATEDIFF(s, '19700101', u.LastActivityDate) LastActivityDate, m.Password, m.PasswordSalt, m.Email, m.IsApproved, m.IsLockedOut, DATEDIFF(s, '19700101', m.CreateDate) CreateDate, DATEDIFF(s, '19700101', m.LastLoginDate) LastLoginDate, m.Newsletter, m.ActivityEmails, m.ActivityMiles, m.IsDeactivated FROM aspnet_Users u
    INNER JOIN aspnet_Membership m ON m.UserId=u.UserId
  ) AS t
WHERE t.rownum BETWEEN {$from} AND {$to}"
);

  file_put_contents('user.log', date('Y-m-d--H:i:s') . " {$from} AND {$to}\n", FILE_APPEND);
 
  // Check if there were any records

  if (!mssql_num_rows($query_result)) {
    $context['results'][] = 'No records found';
  } else {
    while ($row = mssql_fetch_assoc($query_result)) {
      set_time_limit(0);

      //set up the user fields
      $fields = array(
        'name' => $row['UserName'],
        'mail' => strtolower($row['Email']),
        'init' => $row['Email'],
        'pass' => $row['Password'],
        'created' => $row['CreateDate'],
        'access' => $row['LastActivityDate'],
        'login' => $row['LastLoginDate'],
        'status' => ($row['CreateDate']==1 && $row['IsLockedOut']==0 && $row['IsDeactivated']==0) ? 1 : 0,
        'roles' => array('authenticated user'),
      );
      //file_put_contents('user.log', serialize($fields)."\n", FILE_APPEND);

      //the first parameter is left blank so a new user is created
      $account = user_save('', $fields);
     
     
      // Update progress information.
      $context['sandbox']['progress']++;
      $context['sandbox']['current_row'] = $row['rownum'];
      $context['message'] = t('Importing user %username', array('%username' => $fields['name']));
     
      // Store usernames in case the the 'finished' callback wants them.    
      if ($account === FALSE) {
        //$context['results'][] = "{$row['rownum']}-{$context['sandbox']['progress']})) Failed {$fields['name']} <{$fields['mail']}>";
        file_put_contents('user.log', "{$row['rownum']}-{$context['sandbox']['progress']}) Failed {$fields['name']} <{$fields['mail']}>\n", FILE_APPEND);
      } else {
        //$context['results'][] = "{$row['rownum']}-{$context['sandbox']['progress']})) Done #{$account->uid} {$account->name} &lt;{$account->mail}&gt;";
        file_put_contents('user.log', "{$row['rownum']}-{$context['sandbox']['progress']}) Done #{$account->uid} {$account->name} <{$account->mail}>\n", FILE_APPEND);
      }
     
      // Let the batch engine know how close we are to completion.
      if ($context['sandbox']['progress'] == $context['sandbox']['max']) {
        // Done!
        $context['finished'] = 1;
      } else {
        $context['finished'] = $context['sandbox']['progress'] / $context['sandbox']['max'];
      }
    }
    mssql_free_result($query_result);
  }
  mssql_close($connection);
}

Комментарии

Аватар пользователя andreyks andreyks 29 октября 2012 в 1:23

6RUN0, я импортирую пользователей. За одно ознакомился с батчами в друпале.
И собственно два вопроса

1) Если вставлять пользователей напрямик в друпаловскую базу косяки возможны? или лучше продолжать через хуки (user_save)?
2) Что не так с батчем, почему он так медленно отрабатывает?

Аватар пользователя sg85 sg85 29 октября 2012 в 1:52

"andreyks" wrote:
1) Если вставлять пользователей напрямик в друпаловскую базу косяки возможны? или лучше продолжать через хуки (user_save)?

Возможны, если не до конца понимаете что делаете, ибо на каждом сайте поведение будет разное, в зависимости от завязанных на юзерах модулях. При стандартной конфигурации всего 2 таблицы - users и users_roles, стоит включить, например, pathauto, добавится url_alias(хотя алиасы можно и задним числом сделать), про модуль content profile или OG вообще молчу

"andreyks" wrote:
2) Что не так с батчем, почему он так медленно отрабатывает?

"andreyks" wrote:
Отрабатывается 160 раз бустрап, 160 раз подключение к внешней базе (с этим проблем нет) и 16000 раз отрабатывает хук юсер. В чём подвох?

Ради интереса посмотрите сколько времени займет регистрация одного юзера через обычную форму регистрации, а тут 16000 раз.

Аватар пользователя andreyks andreyks 29 октября 2012 в 3:46

"sg85" wrote:
Возможны, если не до конца понимаете что делаете, ибо на каждом сайте поведение будет разное, в зависимости от завязанных на юзерах модулях. При стандартной конфигурации всего 2 таблицы - users и users_roles, стоит включить, например, pathauto, добавится url_alias(хотя алиасы можно и задним числом сделать), про модуль content profile или OG вообще молчу

ага, два профайла, pathauto, privatemsg, logintoboggan, fboauth и другие. Поэтому я и стал с батчем заморачивается.

"sg85" wrote:
Ради интереса посмотрите сколько времени займет регистрация одного юзера через обычную форму регистрации, а тут 16000 раз.

Там бутстрап отрабатывает и иниты всех модулей. Тут на один бутстрап 100 user_save + hook_user ($op='insert')
Меня 100 пользователей в минуту устраивает. Не понятно почему через 2-4 цикла батч на порядок замедляется? ИИ стабильно грузит сервер (апач и мускул)

Аватар пользователя sg85 sg85 31 октября 2012 в 4:13

"andreyks" wrote:
Там бутстрап отрабатывает и иниты всех модулей. Тут на один бутстрап 100 user_save + hook_user ($op='insert')

отработка по времени у них почти одинаковая, вся заморочка как раз в user_save из-за
"andreyks" wrote:
два профайла, pathauto, privatemsg, logintoboggan, fboauth и другие. Поэтому я и стал с батчем заморачивается.

т.е. все эти модули реагируют на user_save, и не только они

"andreyks" wrote:
Не понятно почему через 2-4 цикла батч на порядок замедляется?

а вот такого быть не должно, обычно ошибка в самой логике функции с операциями батча(в т.ч. запросы к бд), сам захожу на форум обычно уже в таком состоянии, что осилить ваш код проблематично.

Аватар пользователя andreyks andreyks 31 октября 2012 в 4:49

"sg85" wrote:
а вот такого быть не должно, обычно ошибка в самой логике функции с операциями батча(в т.ч. запросы к бд), сам захожу на форум обычно уже в таком состоянии, что осилить ваш код проблематично.

Вроде с кодом всё нормально, все действия в лог-файл дублирую. Но почему начинаются тормоза никак понять не могу. Запрос 1 раз на 100 записей и он сравнительно быстро отрабатывает. Всё равно все спасибо. Буду с умным лицом смотреть как бежит батч и целый день пить чаёк))