Делаю импорт пользователей из другого сайта. Без профайлов только имя, емаил, дату регистрации. По 100 штук. Первая сотня добавляется чуть больше минуты, вторая - чуть медленнее, а потом скорость падает до 13 минут за сотню пользователей. Апач и мускул грузят по 50% на intel i3. 16 тыс я просто не дождусь на рабочем ноуте, а на сервере батч вообще после 4-й сотни зависает.
Делал по John K. VanDyk "Pro Drupal Development". Собственные и контриб модули не отключал, но там хук юсер не использовал.
Мне кажется импорт 16 тыс должен занимать не больше 10 минут. Отрабатывается 160 раз бустрап, 160 раз подключение к внешней базе (с этим проблем нет) и 16000 раз отрабатывает хук юсер. В чём подвох?
И ещё вопрос. Если вставлять напрямик в друпаловскую базу косяки возможны? или лучше продолжать через хуки?
Вот основная (operations) функция:
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} <{$account->mail}>";
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);
}
Комментарии
$ mysqldump --opt -u root -p you_database users > users.sql
???
6RUN0, я импортирую пользователей. За одно ознакомился с батчами в друпале.
И собственно два вопроса
1) Если вставлять пользователей напрямик в друпаловскую базу косяки возможны? или лучше продолжать через хуки (user_save)?
2) Что не так с батчем, почему он так медленно отрабатывает?
Возможны, если не до конца понимаете что делаете, ибо на каждом сайте поведение будет разное, в зависимости от завязанных на юзерах модулях. При стандартной конфигурации всего 2 таблицы - users и users_roles, стоит включить, например, pathauto, добавится url_alias(хотя алиасы можно и задним числом сделать), про модуль content profile или OG вообще молчу
Ради интереса посмотрите сколько времени займет регистрация одного юзера через обычную форму регистрации, а тут 16000 раз.
ага, два профайла, pathauto, privatemsg, logintoboggan, fboauth и другие. Поэтому я и стал с батчем заморачивается.
Там бутстрап отрабатывает и иниты всех модулей. Тут на один бутстрап 100 user_save + hook_user ($op='insert')
Меня 100 пользователей в минуту устраивает. Не понятно почему через 2-4 цикла батч на порядок замедляется? ИИ стабильно грузит сервер (апач и мускул)
отработка по времени у них почти одинаковая, вся заморочка как раз в user_save из-за
т.е. все эти модули реагируют на user_save, и не только они
а вот такого быть не должно, обычно ошибка в самой логике функции с операциями батча(в т.ч. запросы к бд), сам захожу на форум обычно уже в таком состоянии, что осилить ваш код проблематично.
Вроде с кодом всё нормально, все действия в лог-файл дублирую. Но почему начинаются тормоза никак понять не могу. Запрос 1 раз на 100 записей и он сравнительно быстро отрабатывает. Всё равно все спасибо. Буду с умным лицом смотреть как бежит батч и целый день пить чаёк))