一、背景
經監控,標籤關係上報20w+的標籤關係處理耗時達到3800多秒。約一個小時
二、問題定位
- 經排查定位到以下代碼耗時佔比最大
- 這段代碼沒有涉及到任務數據庫及外部調用
- 其中的_dataCount總共20w+,證明兩個foreach一共循環了20w+次
三、複雜度分析
1 外層Foreach循環複雜度分析
-
Foreach循環20w+次可知 循環的複雜度O(N)≈20w
2 內層GetDTO方法複雜度分析
- 由於裏面的GetDTO涉及了4個FirstOrDefault(),最大的爲tagRelationsModels,其數據量也爲20w+
- FirstOrDefault()源碼可知其內部也是根據foreach去查找,因此GetDTO方法的複雜度O(M)約等於20w
- FirstOrDefault源碼如下
3 總體複雜度分析
- 總體的複雜度爲O(N*M)≈400億+的計算量
四、優化
1 降低總體複雜度
- 由於外層Foreach的複雜度無法降低,因此主要優化內層GetDTO中的複雜度
- 根據ILookUp源碼可知其複雜度爲O(log2M),20w+的數量在O(log2M)下≈18
- 在儘量不改到原邏輯的情況下,將FirstOrDefault改爲ILookUp
- ILookUp源碼如下
五、總結&數據對比
- 優化後總體的複雜度爲O(N*log2M)≈360w的計算量
- 總計算量由400億降至360萬
- 由於此次優化額外引入了ILookUp,會臨時佔用一部分內存,所以也涉及到了空間換時間的問題
數據量
|
優化前
|
優化後
|
---|---|---|
93000 | 1235秒 | 122秒 |
68000 | 368秒 | 96秒 |