在急切加载include语句时,处理实体框架的性能下降?

时间:2015-07-09 20:32:07

标签: c# asp.net-mvc entity-framework

我试图使用实体框架从一个SQL Server数据库中撤回大量关系,以便在摘要网页上显示,我发现在查询中使用多个include语句的性能非常糟糕。

要求是同时在页面上显示所有单个用户的数据,通常,这不是大量的数据,但是获取它确实需要遍历很多EF关系。查询类似这样的内容

var class = context.Class.Where(a => a.Id.Equals(Id))
                      .Include(a => a.Teacher.Address)
                      .Include(a => a.Teacher.Supplies.Notebooks)
                      .Include(a => a.Teacher.Supplies.Pencils)
                      .Include(a => a.Teacher.Supplies.Textbooks)
                      .Include(a => a.Teacher.Supplies.Erasers)
                      .Include(a => a.Students.Select(d => d.Supplies.Notebooks))
                      .Include(a => a.Students.Select(d => d.Supplies.Pencils))
                      .Include(a => a.Students.Select(d => d.Supplies.Textbooks))
                      .Include(a => a.Students.Select(d => d.Supplies.Erasers))
                      .Include(a => a.Configuration)
                      .Include(a => a.Payment.Payer.Address)
                      .Include(a => a.Payment.PaymentMethod)
                      .First();

对包含最少数据的测试数据库运行需要10秒以上。但是,如果我这样做,性能需要大约1秒钟:

var class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Teacher.Address).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Teacher.Supplies.Notebooks).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Teacher.Supplies.Pencils).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Teacher.Supplies.Textbooks).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Teacher.Supplies.Erasers).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Students.Select(d => d.Supplies.Notebooks)).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Students.Select(d => d.Supplies.Pencils)).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Students.Select(d => d.Supplies.Textbooks)).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Students.Select(d => d.Supplies.Erasers)).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Configuration).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Payment.Payer.Address).First();
    class = context.Class.Where(a => a.Id.Equals(Id)).Include(a => a.Payment.PaymentMethod).First();

这真的是运行查询以获取所有这些数据的最佳方式,还是我完全错误?

2 个答案:

答案 0 :(得分:0)

好吧,我在那里算了18次加入,所以不会以任何方式快速。但是,根据您对此进行测试的方式,您的结果可能会也可能不会很重要。特别是,如果你正在调试或者只是在本地运行,一般来说一切都会变慢。如果您使用的是LocalDb,它将比SQL Server慢。 IIS Express是单线程的,而IIS是多线程的,因此也会对性能产生影响。

首先,您应该在项目中运行Glimpse之类的内容。这样,您实际上可以将加载页面所需的时间与运行查询所需的时间分开,并让您可以查看正在运行的查询的数量和范围。但是,在使用完整的IIS和SQL Server对实际类似生产的计算机进行测试之前,您不会真正知道这将如何执行。

如果这是一个真正的问题,您可以考虑创建一个存储过程来返回所有这些信息。由于SQL Server可以存储执行计划并优化查询,因此这比任何EF都可以做得更快 。如果您发现实体框架对于您的目的而言太慢,您通常也可以调查使用Dapper之类的备用ORM。当然,你会有一个学习曲线,但如果你的主要关注点是性能,你几乎总是比实体框架更好,尽管你可能会失去一些细节。

答案 1 :(得分:0)

不幸的是,我无法解释为什么Include技术如此缓慢,但这就是我尝试获取数据的方式:

var class = context
    .Class
    .Where(a => a.Id.Equals(Id))
    .First()
.Select(a => new 
{
    TA = a.Teacher.Address,
    TN = a.Teacher.Supplies.Notebooks,
    TP =a.Teacher.Supplies.Pencils,
    TT = a.Teacher.Supplies.Textbooks,
    TE = a.Teacher.Supplies.Erasers,
    SN = a.Students.Select(d => d.Supplies.Notebooks),
    SP = a.Students.Select(d => d.Supplies.Pencils),
    ST = a.Students.Select(d => d.Supplies.Textbooks),
    SE = a.Students.Select(d => d.Supplies.Erasers),
    a.Configuration,
    PA = a.Payment.Payer.Address,
    a.Payment.PaymentMethod
};

这会改善表现吗?如果是的话,我会对2种技术生成的sql之间的区别感兴趣