[英]UPDATE query form while loop, code is very slow
我在Laravel App中有以下代碼:我讀取.csv文件中的每一行,並希望更新值。 但是,倍數的更新查詢使用8k行的.csv時非常慢。 我如何加快此代碼的速度? 謝謝
DB::beginTransaction();
try {
$delimiter = ",";
$firstLine = true;
if ($handle !== FALSE) {
$position = 1;
while (($csv_line = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
if ($firstLine == true) {
$firstLine = false;
continue;
}
$player_uid = $csv_line[0];
DB::table('scores')
->where('season_uid', $season_uid)
->where('day', $day)
->where('player_uid', $player_uid)
->update(['position' => $position]);
$position++;
}
fclose($handle);
}
DB::commit();
return true;
} catch (\Exception $e) {
Log::error($e);
DB::rollBack();
return false;
}
MySQL不支持大量更新,但是有一個巧妙的技巧可以使用ON DUPLICATE KEY UPDATE子句用插入替換更新。 這樣,您實際上可以批量更新記錄。 查看此答案以獲取一些示例 。
據我所知,盡管Laravel在其查詢生成器中不支持此子句,所以您將必須手動生成查詢並通過 DB::statement()
發出查詢。確保對傳入的行進行分塊(例如,按100進行分組),您將看到速度顯着提高。
但是請務必意識到,更新8k行並不是一個便宜的操作。 最佳實踐是將其委派給單獨的作業,並在應用程序中設置隊列,以便工作人員可以在后台分別處理這些更新。 您可以在官方文檔中了解有關作業和隊列的更多信息。
確實建議使用單獨的作業來執行此操作,但是您可以嘗試以下代碼。 在https://github.com/laravel/ideas/issues/575上找到了創建單個更新查詢的想法。 這個家伙減少了加載時間,最終快了13倍。
請注意,它之前沒有經過測試。
DB::beginTransaction();
try {
$csv = array_map('str_getcsv', file('data.csv'));
// remove the first line
array_shift($csv);
// grab only the players uids and their positions
$positions = array_flip(array_column($csv, 0));
array_walk($positions, static function(&$position, $id) {
$position = "WHEN {$id} THEN {$position}";
});
DB::update("UPDATE `scores`
SET `position` = CASE `player_uid` " . implode(' ', $positions) . " END
WHERE `player_uid` in (" . implode(',', array_keys($positions)) . ")
AND `session_uid` = ?
AND `day` = ?", [$season_uid, $day]);
DB::commit();
return true;
} catch (\Exception $e) {
Log::error($e);
DB::rollBack();
return false;
}
PS:最好用這種方法撰寫有關性能變化的評論
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.