一. 开发中常见的性能问题
我们在日常开发过程中,由于一些不好的习惯,经常会导致所写的代码性能低下,却毫无发觉,下面就总结一下常见的一些性能问题。
1. 真假分页
① 假分页: db.xxx.toList().Skip(2).take(4) 。
② 真分页:db.xxx.Skip(2).take(3).toList() 。
2. 合理的使用EF的数据加载方式
EF的加载方式有:立即加载、延迟加载、显示加载。
详见:
①: 第五节: EF高级属性(一) 之 本地缓存、立即加载、延迟加载(不含导航属性)
②: 第六节: EF高级属性(二) 之延迟加载、立即加载、显示加载(含导航属性)。
3. NoTracking的使用
EF查询出来的实体,默认是跟踪状态的,如果查询出来的实体不需要修改或者删除,查询的时候可以删除状态跟踪,变为Detached状态,来提高性能。
关于EF状态的跟踪,详见后面章节,敬请期待!!
1 using (DbContext context = new MyDbContext()) 2 { 3 var people = context.Student.Where(p => p.Id > 2).AsNoTracking().ToList(); 4 }
4. 合理的使用SQL事务
将与事务无关的一些SQL语句放到事务外,如果一个事务中的SQL语句过长,很容易出现死锁问题,压力测试时,出现资源被锁的错误。
二. 关于EF数据操作的性能问题
EF自诞生以来,大批量的操作增加、删除、修改操作数据效率一直很低,1000条数据以内,效率尚且可以接受(10s内),但随着数据量逐渐增大,很容易在执行的过程中就宕机了,相当尴尬。在本章节,我们一起来测试一下,EF在不进行任何优化的情况下,几种写法的效率问题。
我们这里的测试是以增加数据为例,先把测试的三种写法的结论贴上。
1. 每添加1条数据,savechange一下(小白常犯的错误,坚决抵制这种做法!!)
1 private static void NewMethod1(DbContext db)2 {3 Console.WriteLine("-------------1. 每添加1条数据,savechange一下(小白常犯的错误,坚决抵制这种做法!!)-------------------");4 Stopwatch watch = Stopwatch.StartNew();5 for (int i = 0; i < 1000; i++)6 {7 TestOne t = new TestOne();8 t.id = Guid.NewGuid().ToString("N");9 t.t1 = "t1+" + i; 10 t.t1 = "t2+" + i; 11 db.Set<TestOne>().Add(t); 12 db.SaveChanges(); 13 } 14 watch.Stop(); 15 Console.WriteLine("1000条数据耗时:{0}", watch.ElapsedMilliseconds); 16 }
2. 先将所有数据添加到内存里,最后再savechange
1 private static void NewMethod2(DbContext db, int count)2 {3 Console.WriteLine("-------------2. 先将所有数据添加到内存里,最后再savechange-------------------");4 Stopwatch watch = Stopwatch.StartNew();5 for (int i = 0; i < count; i++)6 {7 TestOne t = new TestOne();8 t.id = Guid.NewGuid().ToString("N");9 t.t1 = "t1+" + i; 10 t.t1 = "t2+" + i; 11 db.Set<TestOne>().Add(t); 12 } 13 db.SaveChanges(); 14 watch.Stop(); 15 Console.WriteLine("{0}条数据耗时:{1}", count, watch.ElapsedMilliseconds); 16 }
3. 使用addRange方法,先将数据加到list集合中,然后一次性通过addRange加到内存里
1 private static void NewMethod3(DbContext db, int count)2 {3 Console.WriteLine("-------------3. 使用addRange方法,先将数据加到list集合中,然后一次性通过addRange加到内存里-------------------");4 Stopwatch watch = Stopwatch.StartNew();5 List<TestOne> tList = new List<TestOne>();6 for (int i = 0; i < count; i++)7 {8 TestOne t = new TestOne();9 t.id = Guid.NewGuid().ToString("N"); 10 t.t1 = "t1+" + i; 11 t.t1 = "t2+" + i; 12 tList.Add(t); 13 } 14 db.Set<TestOne>().AddRange(tList); 15 db.SaveChanges(); 16 watch.Stop(); 17 Console.WriteLine("{0}条数据耗时:{1}", count, watch.ElapsedMilliseconds); 18 }
总结:EF自有的方法,三个阶段如上,数据超过1000条,性能直线下降,那么怎么来解决EF处理大数据量的性能问题呢?敬请期待下一个章节: 第九节: EF的性能篇(二) 之 Z.EntityFramework.Extensions程序集解决EF的性能问题