iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 19
0
自我挑戰組

花式PHP系列 第 20

Eloquent:以withCount優化

大家知道這個東西嗎?
它也可以幫你透過設定好的關聯,計算出該關聯的數量。

它不是很雞肋嗎?

大部分沒有載入大量資料的場景,你的確不一定要這樣用。

<?php

$factories = FoxconnFactory::select('id', 'address')->with('workers')->get();

$counts = $factories->map(function ($factory) {
    return $factory->workers->count();
})

一般這樣子都還不會造成什麼問題~

但如果你有大量的資料會被載入...

承接上面的程式碼,
如果富士康的員工超級無敵世界宇宙大覺者的多,(訂個數字:122617筆)
那麼在 Laravel 一次把這麼多筆資料撈回來的時候,就會出問題了!

比如說:

  1. where in 的 SQL 長到資料庫的優化器擺爛不想也不能處理
  2. Laravel 會把(一次透過 ids 抓出來的)關聯依序塞回 $factory 中的 $relations

source code
callstack:

  1. Eloquent/Builder::get()
    1. Eloquent/Builder::eagerLoadRelations()
      1. Eloquent/Builder::loadRelation()
        1. $relation->getEager()
        2. $relation->match()

而且別忘了~
Laravel還會對每一個剛撈出來的 model 的資料(attribute)作型別轉換(casts)!

這樣子你應該可以想到不僅資料庫的壓力頗大,
cpu 的壓力更是大到想哭、記憶體也可能回憶起被巨大資料量蹂躪的恐懼。

但我就是要計算它阿

withCount() comes to our rescue!
/images/emoticon/emoticon08.gif

官方英文文件

如果你只是單純的需要計算關聯的數量,並不需要拿關聯的資料來操作,
它可以幫你用 subquery (SQL) 作計算,
並會把它放在「{$relation}_count」這個欄位!

成效

這樣子你就能不免在載入關聯時消耗掉過多的運算資源了!

如果你想衡量這樣作的成效,
我想最好的辦法應該是用 git 開個分支出來,
並搭配 debugbar 比較改動前後,花在運算及 sql 上的時間~


上一篇
Eloquent:深入with
下一篇
GuzzleHttp:併發HTTP REQUEST
系列文
花式PHP31

尚未有邦友留言

立即登入留言