ILookUp的使用场景
一、背景
经监控,标签关系上报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秒 |