我有這個例程從Web服務中獲取一些數據並將其存儲在我的數據庫中。這些數據有20k +項目。爲了將它們保存到數據庫中,我必須首先檢索一些信息然後存儲它們。所以我有這個運行20k +次的foreach循環,每次執行讀取和寫入數據庫。Laravel導入程序隨着時間推移減速
但是這種方法會隨着時間的推移而減慢。完成需要一個多小時!
我已經禁用了查詢日誌(DB::disableQueryLog()
),但是我沒有注意到任何性能上的提升。
這裏是我的代碼:
$data = API::getItems();
foreach ($data as $item) {
$otherItem = OtherItem::where('something', $item['something'])->first();
if (!is_null($otherItem)) {
Item::create([
...
]);
}
}
作爲一個解決方案,我決定預取所有OtherItem
到一個集合,它解決了這個問題:
$data = API::getItems();
$otherItems = OtherItem::all();
foreach ($data as $item) {
$otherItem = otherItems->where('something', $item['something'])->first();
if (!is_null($otherItem)) {
Item::create([
...
]);
}
}
但我想明白爲什麼第一種方法隨着時間的推移急劇減速,做這種事情的最好方法是什麼。
編輯:
澄清: 我知道,做20K的查詢是不是高性能和,在這種情況下,性能並不重要(除非它需要時間,而不是分鐘)。我只會在開發過程中運行這個例程。我最後的做法是兩種答案的混合(我沒有想過緩衝項目並將它們分批插入)。 下面是任何有興趣的代碼:
$data = collect(API::getPrices());
$chunks = $data->chunk(500);
$otherItems = OtherItem::all();
foreach ($chunks as $items) {
$buffer = [];
foreach ($items as $item) {
$otherItem = otherItems->where('something', $item['something'])->first();
if (!is_null($otherItem)) {
$buffer[] = [
...
];
}
}
Item::insert($buffer);
}
那麼,是什麼在困擾我的是,爲什麼是痛苦的緩慢(即使所有的查詢)。我決定做一些基準測試來進一步分析問題。 隨着兩個查詢方法,我得到如下結果:
對於6000循環:
- 最大讀:11.5232小號
- 民閱讀:0.0044小號
平均閱讀:0.3196小號
最大寫:0.9133 s
- 最小寫:0.0007 s
- 平均寫入:0.0085小號
每10-20 iteractions讀取時間上升到了2-3 iteractions這是一個怪異秒,我沒有IDEIA原因。
只是出於好奇,我也基準分塊和緩衝項之間的性差異插入DB之前:
- 沒有緩衝:1 115,4秒(18分鐘35秒)
- 分塊和緩衝:1064。7秒(17分45秒)
您對where子句中使用的'something'字段有索引嗎? –
不,我不知道。我會嘗試。 – flipjms
如果在該字段中沒有索引,則搜索將花費的時間越長,添加到數據庫的項目越多。但無論如何,你的第二個解決方案要好得多。 1查詢與20k查詢。 – Pitchinnate