bullet gem 可能干擾對使用 preload 所造成效能影響的判定
- Backend
- 26 Jul, 2022
最近遇到了一個案例是,有個使用 includes 去 preload association 的地方,相對於直接 pluck 出來,花的時間慢的異常多。研究之後發現是 bullet 的 unused_eager_loading_enable 偵測打開後,會一定程度的影響效能。
如同這位開發者在 issue 所做的說明。unused_eager_loading_enable 有個 O(N²) 複雜度的運算。
原始碼探索
可以看這段程式碼:
這裡會針對每個有載入 association 的 object,一個一個地比對有沒有載入卻沒有使用到的,如果有的話就會產生通知。
而對於每個 object 比對有沒有使用到 association 的方式,則是去比對 object eager load 時一同載入的所有 object 裡,有沒有任何一個 object 有使用到 association,有的話就算數。
因此就產生了 O(N²) 複雜度的運算 N 是 eager load 時總共載入的物件數量。
例如 User.active.includes(:posts) ,如果 User.active 有 1000 個,則會兩層迴圈共約需要 1000 x 1000 個 iteration 去檢查 。
心得
如果有用到 bullet 時,需要注意 bullet 本身會帶來的效能影響,避免誤判 preload 所造成的性能影響。