关于EF中批量添加的个人探索

实际的测试代码和数据记录,还有最终的总结都在下面:

        /// <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 类允许编写提供类似功能的托管代码解决方案

似乎这种效率更高一些(不过,俺没有去测)

参考文献:

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

时间: 2024-10-11 04:53:10

关于EF中批量添加的个人探索的相关文章

EF6基础系列(12)--- EF进行批量添加/删除

EF6添加了批量添加/删除实体集合的方法,我们可以使用DbSet.AddRange()方法将实体集合添加到上下文,同时实体集合中的每一个实体的状态都标记为Added,在执行SaveChange()方法时为每个实体执行Insert操作:同样的我们使用DbSet.RemoveRange()方法将集合中的所有实体都标记为deleted状态,在执行SaveChange()方法时为每一条数据执行delete操作. 通过AddRange()和RemoveRange()方法可以有效提升性能,所以建议在进行不批

解决JavaScript中批量添加事件的问题

这是JavaScript中一个老生常谈的问题,也是初学者较难理解的问题.当给一系列元素添加事件时,常常会出现一些我们不希望出现的问题.例如以下代码: //给li元素批量添加click事件 window.onload = function(){ var lists = document.getElementsByTagName("li"); for(var i=0;i<lists.length;i++){ lists[i].onclick = function(){ alert(i

.Net中批量添加数据的几种实现方法比较

在.Net中经常会遇到批量添加数据,如将Excel中的数据导入数据库,直接在DataGridView控件中添加数据再保存到数据库等等. 方法一:一条一条循环添加 通常我们的第一反应是采用for或foreach循环一条一条的添加. for (int i = 0; i < dgv.Rows.Count; i++) { string sql = "insert into ....."; SqlHelper.ExcuteNonQuery(CommandType.Text, sql, nu

Gitlab(Docker)中批量添加用户及邮件配置

gitlab页面可以添加用户,但是无法批量添加.可以使用api的方式批量添加用户: 1.创建token 在User Setting--Access Tokens中添加token: 复制创建好的token 2.配置脚本及用户信息文件 # vim userinfo.txt name username password user_email 例如: zhangshan zhangshan zhangshan123 [email protected] # vim user_add.sh #!/bin/b

在Office365中批量添加联系人

在O365中,联系人项没有提供批量导入的选项,需要一个一个添加.需要大批量添加时,无疑是一件很痛苦的事! 实际上,我们可以使用Windows PowerShell和CSV文件批量导入联系人.主要分为以下四个步骤: 1.准备CSV文件. 2.建立PowerShell与O365的连接. 3.使用PowerShell命令导入联系人的必需信息. 4.使用PowerShell命令导入联系人的附加信息. 第一步,准备CSV文件 CSV文件的模板已经在附件中(ExternalContacts.rar).CSV

mysql中批量添加一定规则的数据

在工作的过程中遇到问题 测试人员要求添加100个用于用户名为wa000001 - wa000100 其他字段保持不变 简化表数据如下: 表名:t_user   ,user_id 为自增长主键 user_id   user_name 7             wl 9              ee 上面是原有表数据 要实现这个功能可以借助系统表information_schema   实现如下: 定义变量 set @x = 0 select @x :[email protected] +1 s

Linux中批量添加文件和修改文件小笔记

1.#使用通配符批量创建5个文件 $ touch file{1..10}.txt 2.#批量修改这五个后缀名为.txt的文本文件名重命名为.c后缀名结尾的文件 $ rename 's/\.txt/\.c/' *.txt 3.批量就爱那个这五个文件的文件名改为大写 $ rename 'y/a-z/A-Z/' *.c

Kicad中批量添加过孔

布线按V即可插入过孔,但在铺铜,或大电流走线时,有时需要手动添加一些过孔. 但Kicad里面并没有这样的菜单,最后搜索到,要添加过孔时,需要先建立一个单过孔的封装. 然后插入这个封装到PCB.然后修改焊盘的网络名为我们需要的,如GND. 这样就手动插入了一个过孔.然后通过复制及复制为array的功能快速复制为多个. 视频地址:Faking via stitching in KiCad

android批量添加联系人

研究生期间就没写过Java代码了,这几天由于想做一个统计网页词频的工具,但是使用C++不是很方便,于是又用Java做了一个小工具.翻开电脑中以前的文件,发现之前还做过一个android中批量添加联系人的工具,瞬间感觉好亲切,也感叹时间过得好快,一眨眼研究生就快要过完了. 记得当初做这个批量添加联系人的工具是刚来读研时,一大堆新同学的手机号码需要添加,班长整理出来同学们的通讯录后就得一个一个输入联系人和号码到手机中,想想这罪可有的受,于是就想能不能让手机直接读取xls格式(Excel格式)的文件到