近期優化了一個響應速度比較慢的Laravel
專案介面,經過一頓排查,最終發現有幾處程式碼執行時間較慢,其中一處程式碼大致如下:
$keys = Model::query()
->where(...) // 中間一些查詢條件省去
->pluck('id')
->toArray();
這段看起來平平無奇的程式碼執行起來居然要400-500
毫秒!!然後我列印了查詢出來的行數count($keys)
,發現查出的資料大概在1
萬條以上時響應時間就會有明顯的加長。出現這個問題我的第一反應是資料庫查詢響應太慢,但是看了sql
日誌卻發現資料查詢響應時間只要二三十毫秒,這跟想象的完全不一樣,難道laravel
真的有這麼不堪嗎?
需要說明一下,這個專案使用了
laravel-s
加速,已經比常規laravel
專案要快很多。
然後我想了下,也許是因為查出資料後例項化Model
導致的問題? 於是我利用了Builder::macro()
擴充套件了一個cursorPluck
方法,省去查出資料後new Model
的步驟,程式碼大概如下
use Illuminate\Database\Eloquent\Builder;
Builder::macro('cursorPluck', function ($value, $key = null) {
/* @var \Illuminate\Database\Eloquent\Collection $results */
$results = $this->model->newCollection();
$this->select(array_values(array_unique(array_filter([$value, $key]))));
// 這裡直接使用 Illuminate\Database\Query\Builder::cursor() 方法,可以省去例項化 Model 這一步驟
foreach ($this->applyScopes()->query->cursor() as $record) {
$record = is_array($record) ? $record : (array) $record;
if ($key) {
$results->put(($record[$key] ?? null), ($record[$value] ?? null));
} else {
$results->add(($record[$value] ?? null));
}
}
return $results;
});
// 然後上述程式碼更改為
$keys = Model::query()
->where(...)
->cursorPluck('id')
->toArray();
更換了上述程式碼之後效果立竿見影,速度快了許多!程式碼執行由開始的400-500
毫秒下降到100
毫秒左右。
小結
Laravel ORM
在日常開發中給我們帶來諸多便利,但當使用ORM
查詢返回的資料條數較多(幾千上萬條)時,效率會有明顯的下降;此時建議直接返回array
型別資料,直接跳過例項化Model
的步驟,這樣可以明顯減少程式碼的執行時間。
在實際開發中,如果是注重效能的介面應當儘量避免處理大量資料,在此次優化過程中還有一些其他小技巧,後續有時間再分享出來。
本作品採用《CC 協議》,轉載必須註明作者和本文連結