由于之前面试中经常被问到有关EF的数据批量插入问题,今天以Sqlserver数据库为例,对.net中处理数据批量处理的方案进行了测试对比。
1.四种测试方案
(1)普通的EF数据批量插入:即调用DbSet中的Addrange方法
(2)不进行上下文跟踪的EF数据批量插入:即关闭自调用的DetectChanges方法,不对每一个添加的实体进行扫描
(3)在EF中执行sql批量插入
(4)Ado.net执行sql批量插入
(5)利用sqlserver的Bcp功能作批量插入:代码中利用了SqlBulkCopy类
2.相关环境
(1)数据库:sqlserver2014
(2)操作系统:win10
(3)cpu:i5-4210U
(4)内存:8G
3.测试
将以上5种方案,在数据量分别为100,1000,10000,100000的情况下进行测试,每种数据量级别测试3次
要插入的表如下所示:
3.1 普通的EF数据批量插入
用DbSet的AddRange方法作批量插入
3.2 不进行上下文跟踪的EF数据批量插入
用DbSet的AddRange方法作批量插入,且上下文不对增加的实体作跟踪,即代码中将context.Configuration.AutoDetectChangesEnabled设为false
3.3 在EF中执行sql批量插入
3.4 Ado.net执行sql批量插入
3.5 利用sqlserver的Bcp功能作批量插入
SqlBulkCopy类可对sqlserver数据库作批量处理,其原理是利用了sqlserver的Bcp功能,但需要将数据先写入到DataTable
4.测试结果
100条 | 1000条 | 10000条 | 100000条 | |
EF普通批量插入 | 331,41,51 | 1034,459,456 | 5200,5090,4921 | 55396,56479,58018 |
不进行上下文跟踪的EF数据批量插入 | 282,44,55 | 817,1152,547 | 6022,5523,5843 | 51465,52590,52037 |
EF中执行sql批量插入 | 7,4,4 | 52,32,45 | 811,388,380 | 插不进(sqlserver单次sql插入有限制) |
Ado.net执行sql批量插入 | 75,19,49 | 204,225,218 | 2177,2678,2387 | 插不进(sqlserver单次sql插入有限制) |
SqlBulkCopy批量插入 | 26,3,3 | 8,7,10 | 120,114,97 | 820,596,368 |
*注:单位为毫秒
5.结论
(1)利用sqlBulkCopy来对sqlserver作数据批量操作要明显好于其它四种方式,随着数据量增加效果越明显
(2)数据量在1万以内,用EF来做数据插入,其性能基本是能接受的,可以从EF中执行sql批量插入这种方式中看出,所以说ef在正常的业务开发中,数据插入基本不存在性能问题
(3)很奇怪的是EF中执行sql批量插入 这种方式明显好于原生的Ado.net执行sql批量插入这种方式,看来ef还是比较强大的