由于工作中需要对大量数据进行快速校验,试验采用读入内存List实体采用lamdba查找来实现。
实际需求:实际读入内存数据 50W条记录主集数据,还包含约20个子集,子集最大记录数300W条记录。读入内存,校验出结果5分钟之内完成。
测试数据读入内存后占用约2-3G内存。这里测试了多线程读取数据,但提速效果并不明显。SQLServer有自己的SQL执行排队机制(读入数据过程遇到一个小插曲,读入速度慢,占用内存大,无意中发现是把记录照片流也读入了内存。实际处理数据过程并不需要照片信息。去掉后速度提升很大,占用内存也缩小很多,以后遇到类似操作应提前排除这类情况了)
数据校验脚本由另一个同事写的,大约有500个校验,实体字段合法性校验,及主集子集关联检验。开始拿到脚本丢进去测试,结果半个小时也没反应。果断结束进程。然后就是痛苦的优化过程,曾经怀疑这样的方式行不通。差不多用了两周时间,达到5000个主集信息10秒以内完成。50W数据也在3-5分钟完成。最后完成100个并发测试。校验结果正常返回。一切OK现已正常上线使用。
以下是在本次数据校验实现过程中总结出来应注意的一些地方。
1、由原来数据库校验改为内存校验,内存速度更快,数据库校验还会带来并发等待,死锁等问题。
2、加载数据可以采用多线程加载
3、主键使用整形加快查询速度 这一点特别重要,速度提升上千倍。
4、采用lamdba表达式查找数据 用联合查询代替for循环
5、根据数据量的大小采用分别采取线性查找或二分查找提高查询速度
6、共用数据只取一次,在整个校验中全局使用。
并发测试 时发现 静态类中的静态属性不是安全的 因为静态类在内存中只有一份 去掉static 后多线程测试正常
以下为测试数据,及相关说明,可以直接忽略。感兴趣的的可以看看。
1、7万条记录
A01.FindAll(x => !x.PersonStatus.In("01", "02", "03", "04"))
循环查找,共加载15298人,耗时:0.019519秒.
A01.FindAll(x => !(x.PersonStatus == "01" || x.PersonStatus == "02" || x.PersonStatus == "03" || x.PersonStatus == "04"))
循环查找,共加载15298人,耗时:0.0284169秒.
2、3.3万条记录 x.CodeID == "ZB01"的有3300条记录
Codes.FindAll(x => x.CodeID == "ZB01" && (x.CodeItemName == "市辖区" || x.CodeItemName == "县"))
循环查找,共加载287人,耗时:0.0139286秒.
Codes.FindAll(x => x.CodeID == "ZB01" && (x.CodeItemName.In("市辖区", "县")))
循环查找,共加载287人,耗时:0.0230568秒.
3、4000条记录 codeIds有3300条记录
personTableList.A01.FindAll(x => !x.A0114.In(codeIds));
A01 4000条记录 循环查找,共加载0人,耗时:0.1066983秒.
A01 7万条记录 循环查找,共加载0人,耗时:1.7386399秒.
foreach (var A01 in personTableList.A01)
{
if (!codes.Exists(x => x.CodeItemID == A01.A0114))
{
persons.Add(A01);
}
}
上面形式代码,两个列表都是7W条记录时
循环查找,共加载75601人,耗时:55.4800723秒.
循环查找,共加载75601人,耗时:107.4412256秒.
3、
A01.FindAll(x => x.W0111G == "")
循环查找,共加载183人,耗时:0.0039961秒.
A01.FindAll(x => x.W0111G.IsSame(""))
循环查找,共加载183人,耗时:0.0307353秒.
A01.FindAll(x => ids2.IndexOf(x.PersonID)) 最快
A01.FindAll(x => x.PersonID.In(personIds)) 第二
A01.FindAll(x => ids2.Contains(x.PersonID)) 第二
A01.FindAll(x => ids2.Exists(p=>p == x.PersonID)) 最慢
联合查询 速度快
var query = (from A14 in DataList.A14
join A01 in DataList.A01
on A14.ID equals A01.ID
select new { A14.ID, A14.A1407, A01.A0141 }).ToList();
personIds = query.FindAll(x => x.A0141 > x.A1407)
非常重要 主键字段 整形字段比字符串快上百倍
线性查找:Contains,Find,IndexOf都是线性查找。
二分查找:BinarySearch,因为二分查找必须是对有序数组才有效,所以查找前要调用List的Sort方法。
结论:如果List项的个数比较小,用线性查找要略快于二分查找,项的个数越多二分算法优势越明显。可根据实际情况选用适合的查找方式。
测试数据2条
耗时:0.0186627秒.
二分耗时:0.0356611秒.
lamdba 性能测试 大数据内存查找
原文:https://www.cnblogs.com/DevMuYuer/p/9293297.html