這兩天在修改以前的一個功能模組的時候,發現有一短程式碼執行效率非常低,正常只需要幾毫秒就能執行完,卻花了好幾秒,
一步步追蹤下去,發現問題出在集合查詢。
$this->countryReplenish->where('partsId', $asp->partsId)
->where('brandId', $asp->brandId)
->where('countryId', $asp->countryId)
->first();
$this->countryReplenish
是個大小為3W左右的集合。我這樣做的理由是為了減少訪問資料庫次數,從資料庫裡邊把需要用到的資料全部讀出來,以後要用的時候只需要用集合操作。用 microtime(true)
對這段程式碼計時,1.34秒:scream:
多試幾次,還是需要1秒多的時間
當把集合查詢改為資料庫查詢的時候,效率就很高了,幾毫秒就搞定
檢視一下 Collection
where()
方法的原始碼
public function where($key, $operator, $value = null)
{
.
.
.
return $this->filter($this->operatorForWhere($key, $operator, $value));
}
檢視 operatorForWhere()
方法,返回一個閉包
protected function operatorForWhere($key, $operator, $value)
{
return function ($item) use ($key, $operator, $value) {
$retrieved = data_get($item, $key);
.
.
.
}
其中 data_get()
函式包含一個 while 迴圈,時間複雜度為O(n)。
然後結合 filter()
方法過濾,返回一個新集合
public function filter(callable $callback = null)
{
if ($callback) {
return new static(Arr::where($this->items, $callback));
}
return new static(array_filter($this->items));
}
因此當呼叫多個where()
方法時,時間複雜度為O(n m k)。
按照這樣的思路,嘗試只呼叫一次 where()
方法,尷尬的是,還是花了1秒多,效率和多次呼叫 where()
方法差不多。
那麼問題來了,難道集合操作的效率真的很低嗎?
經過查詢資料,答案就在附言中。
本作品採用《CC 協議》,轉載必須註明作者和本文連結