实际的测试代码和数据记录,还有最终的总结都在下面:
/// <summary>/// 这种做法,不用了说了,每次遍历都会打开一次db链接,然后执行insert操作;/// </summary>static void CreateBluckInsertData0(){using (var context = new SiteDbContext()){List<Role> list = new List<Role>();var count = 1000;for (int i = 0; i < count; i++){var entity = new Role(){RoleName = "普通员工" + i};context.Roles.Add(entity);context.SaveChanges();}}}/// <summary>/// 初看,觉得,这样做( context.SaveChanges()方在for循环外面)挺好的,/// 实际跟踪slq发现,还是执行了1000的插入操作,只不过没有在for循环里面;/// 而是在我们的for循环外;总结:不可取;/// </summary>static void CreateBluckInsertData1(){using (var context = new SiteDbContext()){List<Role> list = new List<Role>();var count = 1000;for (int i = 0; i < count; i++){var entity = new Role(){RoleName = "普通员工" + i};context.Roles.Add(entity);}context.SaveChanges();//会增加与数据库的交互次数//EF的一个上下文在提交时会打开一个数据连接,然后把转换成的SQL语句一条一条的发到数据库端,然后去提交 }}/// <summary>/// 拼接字符串;组装后一次性操作;确定,传递的字符数量就会很多;网络压力增加;但不管怎样都比上面两张好;/// </summary>static void CreateBluckInsertData2(){Stopwatch watch = Stopwatch.StartNew();var count = 92000;using (var context = new SiteDbContext()){var bluckString = new StringBuilder();for (int i = 0; i < count; i++){bluckString.Append("INSERT INTO ROLES(RoleName) VALUES('");bluckString.Append("WORKER");bluckString.Append(i);bluckString.Append("');");}var result = bluckString.ToString();Console.WriteLine(string.Format("拼接字符串花费的时间:{0} milliseconds.",watch.ElapsedMilliseconds));//然后这里再来一次性批量的进行插入操作; watch.Restart();context.Database.ExecuteSqlCommand(result);//这样做的好处就是,可以一次性,全部插入,缺点就是;发送大量的insert 文本信息;//1000 customers are created, cost 1777 milliseconds.//5000 customers are created, cost 1906 milliseconds.//9000 customers are created, cost 2354 milliseconds.//9000 customers are created, cost 2023 milliseconds.//这样的计算比较草率; }watch.Stop();Console.WriteLine(string.Format("{0} customers are created, cost {1} milliseconds.", count.ToString(), watch.ElapsedMilliseconds));//结果:拼接字符串花费的时间:97 milliseconds.//12000 customers are created, cost 2028 milliseconds.//拼接字符串花费的时间:99 milliseconds.//22000 customers are created, cost 2336 milliseconds.//拼接字符串花费的时间:118 milliseconds.//92000 customers are created, cost 6553 milliseconds. }/// <summary>/// 这里我们使用第三种方法;/// 网上提供的插件的方法;/// 你以为,插件的方法,就是单纯的封装上面的操作?太年轻了,俺都没监测到一条insert 语句;那么它是怎么做的呢?/// /// </summary>static void CreateBluckInsertData3(){Stopwatch watch = Stopwatch.StartNew();var count = 92000;using (var context = new SiteDbContext()){List<Role> list = new List<Role>();for (int i = 0; i < count; i++){var entity = new Role(){RoleName = "普通员工" + i};list.Add(entity);//context.Roles.Add(entity); //fuck stupid; }Console.WriteLine(string.Format("拼接对象花费的时间:{0} milliseconds.", watch.ElapsedMilliseconds));//然后这里再来一次性批量的进行插入操作; watch.Restart();context.BulkInsert(list);context.BulkSaveChanges();}watch.Stop();Console.WriteLine(string.Format("{0} customers are created, cost {1} milliseconds.", count.ToString(), watch.ElapsedMilliseconds));//1000 customers are created, cost 2865 milliseconds//5000 customers are created, cost 18207 milliseconds.//9000 customers are created, cost 51134 milliseconds. (发现是方法用错了,窝草).不要把 context.Roles.Add(entity); 添加在for循环中;//然后结果是这样的:9000 customers are created, cost 2320 milliseconds.//效率明显比上面的方法提高了很多;//由此可见,我们的批量,效果操作,并不由之前那种方法高呢;//拼接对象花费的时间:102 milliseconds.//12000 customers are created, cost 2238 milliseconds.//拼接对象花费的时间:101 milliseconds. //22000 customers are created, cost 2258 milliseconds.///拼接对象花费的时间:123 milliseconds.// 92000 customers are created, cost 3054 milliseconds.//这种方式的优势就不断体现出来了;//总结,凭借,字段串额效果,要比拼接对象集合的效率要高一些;//然后,就是我们的 }//可能涉及到一些批量数据迁移的时候;///总结:public void Info(){//凭借字段串的效率比拼接对象List的效率要高一些;//方式2的缺点在于,要传送大量的sql语句到我们的db中去执行,//方式3的实现方式和方式一有着本质的区别;是通过;//是数据小于五万条的时候,方式2的效率高,随着数据量的增加;方式3的优势就体现出来了//如果实际的开发中遇到大数据的批量操作;建议还是是用插件方式,就是我们的的方式3;//ps 操作中犯了一个错,是list.add(entity) 而不是 context.Roles.Add(entity); //fuck stupid; }static void Main(string[] args){HibernatingRhinos.Profiler.Appender.EntityFramework.EntityFrameworkProfiler.Initialize();//CreateBluckInsertData1();//CreateDB();//CreateBluckInsertData3();// CreateBluckInsertData2(); Console.ReadLine();}
当然,这里还有我们的另外一种做法;
SqlBulkCopy 接口描述
Microsoft SQL Server 提供一个称为 bcp 的流行的命令提示符实用工具,用于将数据从一个表移动到另一个表(表既可以在同一个服务器上,也可以在不同服务器上)。 SqlBulkCopy 类允许编写提供类似功能的托管代码解决方案
似乎这种效率更高一些(不过,俺没有去测)
阅读资料后,发现,z的扩展插件使用的就是我们的sqlbulkcopy接口滴呀;
大致的流程如下:
- 在SQL Server中创建一张临时表;
- 使用.NET SqlBulkCopy将数据批量插入临时表;
- 在临时表和目标表之间执行一条SQL语句;
- 从SQL Server删除临时表。
参考文献:
http://www.cnblogs.com/gaochundong/p/entity_framework_bulk_insert_extension.html
这里有一偏使用心得:
https://www.cnblogs.com/mobydick/archive/2011/08/28/2155983.html
还有这个:
https://www.cnblogs.com/zfanlong1314/archive/2013/02/05/2892998.html