Entity Framework 使用性能注意事项
最近写一个小应用程序,使用的是EntityFrameowrk框架进行数据库操作,发现一旦数据量大了,复杂了,效率降低十分明显,因此总结了一些性能注意是想(部分是自己的总结,部分是网络穿的:)
1、分页问题
关键问题是在查询完整结果后分页还是在数据库端查询返回前分页的问题。
不合理做法:queryToList().Skip((pageInfo.PageIndex - 1) * pageInfo.PageSize).Take(pageInfo.PageSize);
合理做法:
query.Skip((pageInfo.PageIndex - 1) * pageInfo.PageSize).Take(pageInfo.PageSize).ToList();这样才会在数据库中分页.
2、延迟加载还是预加载(Lazy loading vs egg loading)
关键在于复杂度,如果不是十分复杂的话,那么通过预加载将大大降低sql语句的数量(访问db的次数)从而提升效率
例子代码(延迟加载)
using (SchoolContainer db = new SchoolContainer())
{
var list = db.People.Where(ent => ent.PersonID < 30).ToList();
foreach (var people in list)
{
foreach (var ent in people.StudentGrades)
{
Console.WriteLine(ent.Grade);
}
}
}
如果启用延迟加载,这样会造成多次往返预加载.代码如下:
var list = db.People.Include("StudentGrades").Where(ent => ent.PersonID < 30).ToList();
3、事务的简单性
应尽量把查询语句或者其他响事务外的语句移在事务外执行.不然让一个事务的时间太长了,就容易引起资源死锁的问题。
4、NoTracking的使用(不修改不删除)
其实很简单,就是在处理只是现实或者判断的entity的时候,我们可以放弃entity关联的状态和db相关信息,这样实体的状态会是Detached状态。
using (var context = new MyDbContext())
{
var people = context.People.Where(p => p.PersonID > 100).AsNoTracking().ToList();
}
当然也可以通过context.People.MergeOption = System.Data.Objects.MergeOption.NoTracking;来统一设置。
5、批量删除和修改
尽量应该使用自定义的sql语句来完成,而不是通过Entity来完成。
6.使用已编译的查询,虽然到EF5.0, LINQ 查询是自动缓存的.但使用编译查询会比自动缓存的效率高.
6、使用编译查询
如果应用程序需要在实体框架中多次执行结构上类似的查询,则通常可以通过编译一次查询然后使用不同参数多次执行查询的方法来提高性能。 例子如下:
static readonly Func<AdventureWorksEntities, Decimal> s_compiledQuery3MQ = CompiledQuery.Compile<AdventureWorksEntities, Decimal>(
ctx => ctx.Products.Average(product => product.ListPrice));
static void CompiledQuery3_MQ()
{
using (AdventureWorksEntities context = new AdventureWorksEntities())
{
Decimal averageProductPrice = s_compiledQuery3MQ.Invoke(context);
Console.WriteLine("The average of the product list prices is $: {0}", averageProductPrice);
}
}
7、不适用临时的数据类型(view),而应该是用预先生成的view,大大提高效率;
具体其他相关性能分析,可以查询msdn的http://msdn.microsoft.com/zh-cn/library/cc853327.aspx