Иногда необходимо обновить данные в базе данных. Самая простая возможность — просто запустить обновление в базе данных MySQL. Это не всегда работает. Особенно, когда вы используете события или вы также хотите возобновить отношения ....
Команды
В этом случае я рекомендую создать Command. Даже для разовых изменений.
php artisan make:command YourCommandName
Индикатор прогресса
Первым советом будет использование индикатора выполнения. В долгосрочных командах полезно видеть, что прогресс есть.
Чтобы показать вам, как я просто копирую пример из Laravel Documentation.
$users = App\Models\User::all();
$bar = $this->output->createProgressBar(count($users));
$bar->start();
foreach ($users as $user) {
$this->performTask($user);
$bar->advance();
}
$bar->finish();
Он
отлично подходит для пары сотен записей с легкими изменениями. Если вы хотите изменить больше записей с большей сложностью, вы должны использовать результаты поиска.
Проблема в том, что если вы загрузите все в свою красноречивую коллекцию, ваш ягненок будет ограничением. Чтобы избежать этого, вы можете использовать встроенную часть функции Laravel в своих запросах для последовательного повторения таблицы.
App\Models\User::chunk(200, function ($users){
foreach($users as $user){
$user->name .= ' :)';
$user->save();
}
});
Одна важная вещь, которую следует понимать в функции фрагмента, заключается в том, чтобы понять, как выполняются запросы. В этом примере после итерации 200 пользователей базовый запрос снова выполняется с функцией LMIT в таблице.
Представьте, что у вас этот случай
App\Models\User::where('active', true)
->chunk(200, function ($users){
foreach($users as $user){
$user->active = false;
$user->save();
}
});
В этом коде он превысит 200 пользователей, изменив активное значение на false. Во втором запуске он снова запросит базу данных для пользователей, у которых есть активная правда. Проблема в том, что, поскольку мы только что изменили активный статус 200 пользователей, мы бы получили список без них. Но функция Limit ограничит результат от 200 до 400 в результатах. Это означает, что нам будет не хватать 200 пользователей, которых мы действительно хотели изменить.
Laravel имеет функцию преодоления проблемы, просто важно понимать, когда его использовать. Так что решение в данной ситуации будет.
App\Models\User::where('active', true)
->chunkById(200, function ($users){
foreach($users as $user){
$user->active = false;
$user->save();
}
});
Транзакции базы данных
Теперь мы можем вносить много изменений в наши модели, и мы избегаем проблемы того, что наши красноречивые коллекции становятся слишком большими.
Но в нашем последнем примере мы выполним обновленную инструкцию для каждого отдельного пользователя нашей базы данных. Чтобы этого избежать, я посчитал хорошей тактикой использование транзакций.
Это позволяет нам повторно использовать наши части и обновлять БД до фрагмента.
App\Models\User::where('active', true)
->chunkById(200, function ($users){
try {
DB::beginTransaction();
foreach($users as $user){
$user->active = false;
$user->save();
}
DB::commit();
} catch (\Exception $e) {
//handle your error (log ...)
DB::rollBack();
}
});
В этом примере кода мы объединяем chunkById с транзакциями базы данных. Это может сэкономить много времени на обновление базы данных. Подробнее о транзакциях Database можно прочитать в документации Laravel.
Транзакции могут вызвать проблемы, если они используются неправильно. Если вы забудете сделать или откатитесь назад, вы создадите вложенные транзакции. Вы можете прочитать больше в Blogpost
Объедините его вместе
Чтобы завершить этот пример кода, мы можем повторно ввести индикатор
$count = App\Models\User::where('active', true)->count();
$bar = $this->output->createProgressBar($count);
$bar->start();
App\Models\User::where('active', true)
->chunkById(200, function ($users){
try {
DB::beginTransaction();
foreach($users as $user){
$user->active = false;
$user->save();
$bar->advance();
}
DB::commit();
} catch (\Exception $e) {
//handle your error (log ...)
DB::rollBack();
$bar->finish();
}
});
$bar->finish();
выполнения. Итак, это моя стратегия обработки обновлений больших наборов данных. Вы можете изменить размер фрагмента в соответствии с вашими потребностями и экспериментами, что принесет вам хорошие результаты. По моему опыту, что-то из 200 - 1000 - это нормально.
Иногда, особенно когда расчет для одной записи усложняется, я вижу, что весь процесс замедляется после каждой обработки. Он начинается примерно с 2 секунд на перекладине, чтобы двигаться до 30 или 40 секунд. Поскольку я испытал это в разных командах, я не уверен, что это общая тема. Если у кого-то есть какая-либо информация об этом, дайте мне знать.
Я надеюсь, что эта статья поможет вам.