EntityFramework6学习总结7(增删改性能优化)

当操作大量数据时,EF框架提供的数据操作方法就显得非常慢,可以利用第三方插件来提升数据操作性能。

下面的实例统一用日志表来测试,表结构如下:

数据新增

使用EF原生方法,插入一万条数据到数据库中:

using (NewsDbContext dbContext = new NewsDbContext())
            {
                dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                {
                    Stopwatch watch = Stopwatch.StartNew();
                    for (int i = 0; i < 10000; i++)
                    {
                        NewsLog log = new NewsLog()
                        {
                            OperateUserID = i,
                            OperateDate = DateTime.Now.AddDays(2),
                            LogContent = "我是通过普通方法第二次插入的第" + i + "条数据"
                        };
                        dbContext.NewsLogs.Add(log);
                    }

                    dbContext.SaveChanges();//新增
                    watch.Stop();
                    Console.WriteLine($"10000条数据EF常规方法新增耗时:{watch.ElapsedMilliseconds}");
                }
}

执行结果: 

执行了75秒

利用插件SqlBulkCopy插入一万条数据:

要使用此插件,首先要引用程序集System.Data.SqlClient

代码实例: 

using (NewsDbContext dbContext = new NewsDbContext())
            {
                dbContext.Database.Log += c => Console.WriteLine($"sql:{c}");

                {
                    Stopwatch watch = Stopwatch.StartNew();

                    //一. 构造DataTable结构并且给其赋值
                    //1.定义与目标表的结构一致的内存表 排除自增id列  
                    DataTable dtSource = new DataTable();
                    //列名称如果和目标表设置为一样,则后面可以不用进行字段映射  
                    dtSource.Columns.Add("OperateDate");
                    dtSource.Columns.Add("OperateUserID");
                    dtSource.Columns.Add("LogContent");
                    //2. 向dt中增加4W条测试数据  
                    DataRow dr;
                    for (int i = 0; i < 10000; i++)
                    {
                        // 创建与dt结构相同的DataRow对象  
                        dr = dtSource.NewRow();
                        dr["OperateDate"] = DateTime.Now.AddDays(1);
                        dr["OperateUserID"] = i;
                        dr["LogContent"] = "我是通过扩展方法SqlBulkCopy插入的第" + i + "条数据";

                        // 将dr追加到dt中  
                        dtSource.Rows.Add(dr);
                    }

                    AddByBluckCopy(dtSource, "NewsLog");

                    watch.Stop();
                    Console.WriteLine($"10000条数据EF扩展方法新增耗时:{watch.ElapsedMilliseconds}");
                }
}
        /// <summary>
        /// 海量数据插入方法
        /// (调用该方法需要注意,DataTable中的字段名称必须和数据库中的字段名称一一对应)
        /// </summary>
        /// <param name="table">内存表数据</param>
        /// <param name="tableName">目标数据的名称</param>
        public static void AddByBluckCopy(DataTable table, string tableName)
        {
            string connStr = ConfigurationManager.ConnectionStrings["NewsDbContext"].ToString();//数据库链接

            if (table != null && table.Rows.Count > 0)
            {
                using (SqlBulkCopy bulk = new SqlBulkCopy(connStr))
                {
                    bulk.BatchSize = 1000;
                    bulk.BulkCopyTimeout = 100;
                    bulk.DestinationTableName = tableName;

                    //设置列映射关系
                    bulk.ColumnMappings.Add("OperateDate", "OperateDate");
                    bulk.ColumnMappings.Add("OperateUserID", "OperateUserID");
                    bulk.ColumnMappings.Add("LogContent", "LogContent");

                    bulk.WriteToServer(table);
                }
            }
        }

 数据库连接在App.config中配置

 执行结果: 

可以看到通过插件的方式只用了0.49秒,速度提升了很多。

数据修改和数据删除引用的第三方库是另外一个,程序集名字 Z.EntityFramework.Extensions 

有关此程序集的官方文档:https://entityframework-plus.net/batch-delete

下面实例中只是用到了最基本的方法,其中还有很多其他用法,可以参考官方文档。

数据修改

使用EF原生方法修改一万条记录:

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    Stopwatch watch = Stopwatch.StartNew();

                    var list = dbContext.NewsLogs.Where(x => 1 == 1);
                    foreach (var item in list)
                    {
                        item.LogContent += "测试";
                    }

                    dbContext.SaveChanges();

                    watch.Stop();
                    Console.WriteLine($"10000条数据使用EF原生方法修改耗时:{watch.ElapsedMilliseconds}");
                }

执行结果: 

执行耗时4.5秒。看起来使用原生方法更新数据效率还可以,不是很慢。

因为数据库的表中一共有一万条数据,所以where条件中写了1==1,就是更新所有记录。

使用第三方插件修改一万条数据:

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    Stopwatch watch = Stopwatch.StartNew();

                    int count = dbContext.Set<NewsLog>().Where(u => 1 == 1).Update(x => new NewsLog()
                    {
                        LogContent = "我是修改后的值"
                    });

                    watch.Stop();
                    Console.WriteLine($"10000条数据使用扩展方法修改耗时:{watch.ElapsedMilliseconds}");
                }

执行耗时1.7秒。

数据删除

使用EF原生方法删除一万条记录:

 using (NewsDbContext dbContext = new NewsDbContext())
                {
                    var list = dbContext.Set<NewsLog>().Where(u => u.Id <= 10000).ToList();
                    Stopwatch watch = Stopwatch.StartNew();

                    foreach (var item in list)
                    {
                        dbContext.Entry(item).State = EntityState.Deleted;
                    }
                    int count = dbContext.SaveChanges();
                    watch.Stop();
                    Console.WriteLine($"10000条数据EF常规方法删除耗时:{watch.ElapsedMilliseconds}");
                }

执行结果: 

普通方法删除一万条数据耗时76秒。

使用第三方插件删除一万条数据:

                using (NewsDbContext dbContext = new NewsDbContext())
                {
                    Stopwatch watch = Stopwatch.StartNew();

                    dbContext.NewsLogs.Where(x => x.Id <= 20000)
                             .Delete();

                    watch.Stop();
                    Console.WriteLine($"10000条数据使用插件方法删除耗时:{watch.ElapsedMilliseconds}");
                }

使用插件删除一万条数据耗时1.6秒,速度是非常快的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值