EntityFramework指量添加大数据如何处理性能问题

做一个批量发消息的功能,要向消息表中批量写入数据,用的是微软的EF框架的插入方法;发现就10000条数据就耗时好几分钟,对应追求用户体验的我来说这是极不能容忍的,后来改为拼接SQL,性能提高了好几倍;现在来分享一下经验:

原始的方法类似这种:

public ActionResult Add(ItemDetails entity)
        {
            var sw = new Stopwatch();
            sw.Start();
            using (db)
            {
                for (var i = 0; i < 10000; i++)
                {
                    db.ItemDetails.Add(entity);
                    db.SaveChanges();
                }
            }
            sw.Stop();
            var date = sw.Elapsed;
            return Json(string.Format("总耗时:{0}", date));
        }

来看看添加10000条数据耗时:

就10000条数据就耗时这么久,要是上百万的数据量,那简直就不能想象,再来看看优化后的:

生成SQL的方法:

public class ItemDetailBatch
    {
        public static string BatchAdd(ItemDetails entity)
        {
            SqlParameter [] paras=
            {
                new SqlParameter("@Item_Name",SqlDbType.VarChar,100), 
                new SqlParameter("@Item_Price",SqlDbType.Int), 
                new SqlParameter("@Image_Name",SqlDbType.VarChar,100), 
                new SqlParameter("@Description",SqlDbType.VarChar,100),
                new SqlParameter("@AddedBy",SqlDbType.VarChar,100)
            };
            paras[0] .Value= entity.Item_Name;
            paras[1].Value = entity.Item_Price;
            paras[2].Value = entity.Image_Name;
            paras[3].Value = entity.Description;
            paras[4].Value = entity.AddedBy;
            var sb=new StringBuilder();
            sb.Append("insert into ItemDetails (Item_Name,Item_Price,Image_Name,Description,AddedBy) ");
            sb.AppendFormat("values ('{0}',{1},'{2}','{3}','{4}')", paras[0].Value, paras[1].Value, paras[2].Value,paras[3].Value, paras[4].Value);
            return sb.ToString();
        }
    }

 

Controller层调用:

public ActionResult Add(ItemDetails entity)
        {
            var sw = new Stopwatch();
            sw.Start();
            using (var db = new ShoppingDBConn())
            {
                var sql = new StringBuilder();
                for (int i = 0; i < 10000; i++)
                {
                    //生成SQL
                    sql.Append(ItemDetailBatch.BatchAdd(entity));
                }
                //一次性执行SQL
                db.Database.ExecuteSqlCommand(sql.ToString());
            }
            sw.Stop();
            var date = sw.Elapsed;
            return Json(string.Format("总耗时:{0}", date));
        }

        
界面数据:

同样10000条总耗时:

EF没添加一次都要向数据库提交一次,而直接拼接SQL的方法就是减少与数据库的交互次数,一次性提交执行所有数据;

继续讨论上面问题

上面的文章经纶有很多人在吐槽,很多人说说把SaveChanges()放在for循环外面,我不知道他们有没有亲自去尝试过,反正我尝试了,然而并没什么卵用。

下面是我按照他们说的进行更改后的代码:

public ActionResult Add(ItemDetails entity)
        {
            var sw = new Stopwatch();
            var count = 0;
            //var counts = 0;
            sw.Start();
            using (var db = new ShoppingDBConn())
            {
                for (var i = 0; i < 10000; i++)
                {
                    var data = new ItemDetails
                    {
                        AddedBy = entity.AddedBy,
                        Description = entity.Description,
                        Image_Name = entity.Image_Name,
                        Item_Name = entity.Item_Name,
                        Item_Price = entity.Item_Price
                    };
                    db.ItemDetails.Add(data);
                }
                count = db.SaveChanges();
            }
            sw.Stop();
            var date = sw.Elapsed;
            return Json(string.Format("总耗时:{0},添加数量:{1}", date, count));
        }

运行耗时:

 
 

再看看AddRange方式:

public ActionResult Add(ItemDetails entity)
        {
            var sw = new Stopwatch();
            var count = 0;
            //var counts = 0;
            sw.Start();
            using (var db = new ShoppingDBConn())
            {
                var list = new List<ItemDetails>();
                for (var i = 0; i < 10000; i++)
                {
                    list.Add(new ItemDetails
                    {
                        AddedBy = entity.AddedBy,
                        Description = entity.Description,
                        Image_Name = entity.Image_Name,
                        Item_Name = entity.Item_Name,
                        Item_Price = entity.Item_Price
                    });
                }
                db.ItemDetails.AddRange(list);
                count = db.SaveChanges();
            }
            sw.Stop();
            var date = sw.Elapsed;
            return Json(string.Format("总耗时:{0},添加数量:{1}", date, count));
        }

耗时情况:

 
不过还好有几位给出了很好的建议,用SqlBulkCopy,下面是优化后的代码,比上面任何一种都要快好几倍:

public void BulkInsertAll<T>(IEnumerable<T> entities)  
        {
            entities = entities.ToArray();
            var cons=new ShoppingDBConn();
            string cs = cons.Database.Connection.ConnectionString;
            var conn = new SqlConnection(cs);
            conn.Open();
            Type t = typeof(T);
            var bulkCopy = new SqlBulkCopy(conn)
            {
                DestinationTableName = t.Name
            };
            var properties = t.GetProperties().Where(EventTypeFilter).ToArray();
            var table = new DataTable();
            foreach (var property in properties)
            {
                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType &&
                    propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }
                table.Columns.Add(new DataColumn(property.Name, propertyType));
            }
            foreach (var entity in entities)
            {
                table.Rows.Add(properties.Select(
                  property => GetPropertyValue(
                  property.GetValue(entity, null))).ToArray());
            }
            bulkCopy.WriteToServer(table);
            conn.Close();
        }
        private bool EventTypeFilter(System.Reflection.PropertyInfo p)
        {
            var attribute = Attribute.GetCustomAttribute(p,
                typeof(AssociationAttribute)) as AssociationAttribute;
            if (attribute == null) return true;
            if (attribute.IsForeignKey == false) return true;
            return false;
        }
        private object GetPropertyValue(object o)
        {
            if (o == null)
                return DBNull.Value;
            return o;
        }

调用该方法:

public ActionResult Add(ItemDetails entity)
        {
            var sw = new Stopwatch();
            var count = 0;
            //var counts = 0;
            sw.Start();
            using (var db = new ShoppingDBConn())
            {
                var list = new List<ItemDetails>();
                for (var i = 0; i < 10000; i++)
                {
                    list.Add(new ItemDetails
                    {
                        AddedBy = entity.AddedBy,
                        Description = entity.Description,
                        Image_Name = entity.Image_Name,
                        Item_Name = entity.Item_Name,
                        Item_Price = entity.Item_Price
                    });
                    count++;
                }
                BulkInsertAll(list);
            }
            sw.Stop();
            var date = sw.Elapsed;
            return Json(string.Format("总耗时:{0},添加数量:{1}", date, count));
        }

总耗时情况:

由上对比我们可以看出,下面讲的拼接SQL都要快好几倍。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索sql
, 框架
, 大数据
, 数据
, 用户体验
using
entity framework性能、添加entityframework、entity framework、entity framework 6、c entity framework,以便于您获取更多的相关知识。

时间: 2024-08-31 04:56:48

EntityFramework指量添加大数据如何处理性能问题的相关文章

.NET批量大数据插入性能分析及比较

原文:.NET批量大数据插入性能分析及比较   数据插入使用了以下几种方式 1. 逐条数据插入2. 拼接sql语句批量插入3. 拼接sql语句并使用Transaction4. 拼接sql语句并使用SqlTransaction5. 使用DataAdapter6. 使用TransactionScope及SqlBulkCopy7. 使用表值参数   数据库使用SQL Server,脚本如下   create table TestTable(Id int ,Name nvarchar(20))   程序

入主恒生电子意图暴露 马云被指觊觎金融大数据

中介交易 SEO诊断淘宝客 站长团购 云主机 技术大厅 本报记者 安丽芬 广州报道 阿里巴巴创始人马云在不同场合坦承过自己是"搅局者".如今的基金.证券.银行甚至足球行业,似乎都已成为马云要撼动的领域. 马云的即将入主,同样在搅动着恒生电子所在的江湖. 7月6日,有媒体报道称"6月27日,恒生电子032投资管理系统出现重大事故,多家使用该系统的金融机构无法正常下单交易,其中信托(受托阳光私募)影响最为严重",并称"浙江融信的人马开始进驻恒生电子,导致公司在

国内首个大数据平台性能标准制定完成

今天越来越多的企业认识到,大数据的掌控和分析能力将成为竞争力的核心,企业对大数据的投资也在不断扩大.Gartner调查显示,73%的企业计划在未来两年内投资大数据.以开源Hadoop.Spark等为基础的大数据基础平台解决方案和云服务如雨后春笋不断涌现,形成了近200亿美元的市场规模.然而对于很多企业用户来说,如何评价一个大数据平台的综合能力,常常是选型.平台建设和系统优化时面临的一大挑战.目前来看,国内外还缺乏一套能体现大数据特点,又简便易行,且被工业界广泛认可的大数据平台性能测试标准与工具.

泰一指尚董事长江有归任浙大“大数据跨界服务科技联盟指导委员会”委员

4月19日,浙江大学西湖学术论坛第138次会议顺利召开,"大数据跨界服务科技联盟"发布最新战略研讨成果,并正式聘任泰一指尚董事长江有归为浙江大学大数据跨界服务科技联盟指导委员会委员. [泰一指尚董事长江有归被聘任为浙江大学大数据跨界服务科技联盟指导委员会委员 ] 面对国家对科技产业的大力扶持及中国产业重大调整问题,联盟能够充分发挥交叉优势,开展大项目凝练与攻关工作,承担争取多项重大科技专项:采取线上线下多种形式,开展联盟成果的应用辐射工作,形成我国大数据跨界服务领域有影响力平台成果.泰

100个常用大数据词汇中英文对照表

文章讲的是100个常用大数据词汇中英文对照表,常用大数据词汇中英文对照表 A 聚合(Aggregation) – 搜索.合并.显示数据的过程 算法(Algorithms) – 可以完成某种数据分析的数学公式 分析法(Analytics) – 用于发现数据的内在涵义 异常检测(Anomaly detection) – 在数据集中搜索与预期模式或行为不匹配的数据项.除了"Anomalies",用来表示异常的词有以下几种:outliers, exceptions, surprises, co

常见的大数据术语表(中英对照)

大数据的出现带来了许多新的术语,但这些术语往往比较难以理解.因此,我们通过本文给出一个常用的大数据术语表,抛砖引玉,供大家深入了解.其中部分定义参考了相应的博客文章.当然,这份术语表并没有100%包含所有的术语,如果你认为有任何遗漏之处,请告之我们. A 聚合(Aggregation) – 搜索.合并.显示数据的过程 算法(Algorithms) – 可以完成某种数据分析的数学公式 分析法(Analytics) – 用于发现数据的内在涵义 异常检测(Anomaly detection) – 在数

大数据的安全理解及应对策略研究

1.引言 大数据的产生使数据分析与应用更加复杂,难以管理.据统计,过去3年里全球产生的数据量比以往400年的数据加起来还多,这些数据包括文档.图片.视频. Web页面.电子邮件.微博等不同类型,其中,只有20%是结构化数据,80%则是非结构化数据.数据的增多使数据安全和隐私保护问题日渐突出,各类安全事件给企业和用户敲醒了警钟.在整个数据生命周期里,企业需要遵守更严格的安全标准和保密规定,对数据存储与使用的安全性和隐私性要求越来越高,传统数据保护方法常常无法满足新变化网络和数字化生活也使黑客更容易

《大数据导论》一1.2 大数据特征

  本节书摘来自华章出版社<大数据导论>一书中的第1章,第1.2节,作者托马斯·埃尔(Thomas Erl),瓦吉德·哈塔克(Wajid Khattak),保罗·布勒(Paul Buhler),更多章节内容可以访问"华章计算机"公众号查看. 1.2 大数据特征 大数据的数据集至少拥有一个或多个在解决方案设计和分析环境架构中需要考虑的特征.这些特征大多数由道格·兰尼早在2001年发布的一篇讨论电子商务数据的容量.速率和多样性对企业数据仓库的影响的文章中最先提出.考虑到非结构化

大数据平台架构技术选型与场景运用

一.大数据平台 大数据在工作中的应用有三种: 与业务相关,比如用户画像.风险控制等; 与决策相关,数据科学的领域,了解统计学.算法,这是数据科学家的范畴; 与工程相关,如何实施.如何实现.解决什么业务问题,这是数据工程师的工作. 数据工程师在业务和数据科学家之间搭建起实践的桥梁.本文要分享的大数据平台架构技术选型及场景运用偏向于工程方面. 如图所示,大数据平台第一个要素就是数据源,我们要处理的数据源往往是在业务系统上,数据分析的时候可能不会直接对业务的数据源进行处理,而是先经过数据采集.数据存储