Іноді потрібно оновити дані у своїй базі даних. Найпростіша можливість - просто запустити оновлення у своїй базі даних 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 з транзакціями бази даних. Це може заощадити багато часу на оновлення БД. Детальніше про Транзакції бази даних ви можете прочитати в документації 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 секунд. Оскільки я відчував це за різними командами, я не впевнений, що це загальна тема. Якщо хтось має будь-яку інформацію про це, повідомте мене про це.
Сподіваюся, ця стаття вам допоможе.