2016-11-10 230 views
4

我们有一个需要大约10秒才能完成的EF4查询。该查询并不复杂,但由于包含很多相关表格,所以需要很长时间。我试图加快速度。为什么这个EF查询需要这么长时间?

原始查询看起来是这样的(简称为清楚起见)...

var supportTickets = ctx.SupportTickets 
    .Include(s => s.System.Customer.Country) 
    .Include(s => s.System.Site.Address.Country) 
    // other includes omitted 
    .OrderByDescending(s => s.ID) 
    .ToList(); 
var ticketsList = supportTickets 
    .Select(CreateSupportTicketListOverview) 
    .ToList(); 

CreateSupportTicketListOverview()是采取实体和返回基于它DTO的方法。它的缩短版本看起来像这样...

private static SupportTicketListOverview CreateSupportTicketListOverview(SupportTicket x) 
    { 
    return new SupportTicketListOverview { 
     ID = x.ID, 
     SystemNumber = x.System != null ? x.System.SystemNumber : "", 
     CustomerName = x.System != null && x.System.Customer != null ? x.System.Customer.Name : "", 
     ShortSummary = x.ShortSummary, 
     SiteName = x.Site != null ? x.Site.SiteName : "", 
     Status = x.Status != null ? x.Status.Description : "", 
     // other properties omitted for clarity 
    }; 
    } 

正如我所说,这需要大约10秒,并返回刚刚结果不到4000。 SQL Server Profiler显示查询花费了大约6.6秒。如果我们复制生成并自行运行的SQL,它只需要大约2秒钟,这使我感到困惑。为什么自行运行时速度更快?创建实体所需的时间不会包含在数据库查询中吗?如果是这样,那么剩下的时间花在做什么?

我试图通过关闭跟踪并从数据库中提取所需的数据而不是完整的实体来改善这一点。修改后的代码看起来像这样(为了清晰再次缩短)...

var tickets = ((SalesTrackerCRMEntities) getContext()).SupportTickets 
     .AsNoTracking() 
     .Include(s => s.System.Customer.Country) 
     .Include(s => s.System.Site.Address.Country) 
     .OrderByDescending(s => s.ID) 
     .Select(t => new { 
     SystemNumber = t.System != null ? t.System.DHRNumber : "", t.ID, 
     CustomerName = t.System != null && t.System.Customer != null ? t.System.Customer.Name : "", 
     SiteName = t.Site != null ? t.Site.SiteName : "", 
     Status = t.Status != null ? t.Status.Description : "", 
     // other stuff omitted 
     }) 
     .AsEnumerable(); 
    var tickets1 =tickets 
     .Select(t => new SupportTicketListOverview { 
     ID = t.ID, 
     SystemNumber = t.SystemNumber, 
     CustomerName = t.CustomerName, 
     ShortSummary = t.ShortSummary, 
     SiteName = t.SiteName, 
     Status = t.Status, 
     // other stuff omitted 
     }) 
     .ToList(); 

令我吃惊的是,这花了大约15秒钟才完成。在剖析器中,数据库查询本身花费了大约0.7s,即比原始查询快的十倍,但EF查询总体花费了50%较长的

所以我完全困惑。我做了一些搜索,但是我发现的所有建议都是针对我已经在做的事情。例如,this blog post提供了七种提高EF性能的方法。这些包括不使用存储库模式(不确定他在这里的意思,因为他没有显示任何如何做或不做的例子),不使用分页(我们没有),使用预测(我们是,至少在新的查询中),关闭延迟加载(它已经关闭),关闭跟踪(已经完成)并在表上使用索引(我们已经是)。最后的技巧是减少查询次数。由于我们需要所有相关数据,因此无法看到我们在这里如何做到这一点。

总之,原始数据库查询需要6.6s,整个EF查询需要10s。修改后的查询需要数据库部分为.7s,而整个EF查询需要15s。所有这些都太长了。

是否有人能够建议我如何加快查询?谢谢

+0

您的数据库服务器位于其他地区吗?当我的azure web应用程序在美国地区托管并且我的数据库(错误地)在巴西地区时,我有(类似)类似的问题。 – Developer

+1

您的表访问正确索引? EF4在组装一个体面的查询方面很糟糕。 –

+2

http://stackoverflow.com/questions/2876616/returning-ienumerablet-vs-iqueryablet – Hackerman

回答

0

你正在使用什么版本的SQL Server?如果是2016年,您可以启用Query Store(https://msdn.microsoft.com/en-us/library/dn817826.aspx)并查找EF4查询正在执行的t-sql查询。如果它的版本较旧,则可以在EF4查询运行时使用此(http://blog.sqlauthority.com/2009/01/07/sql-server-find-currently-running-query-t-sql/)来查找查询文本,并查看为什么查询速度较慢,方法是针对服务器运行并分析计划/缺失索引/等。

+0

谢谢,但正如我在我原来的问题中所说的,如果我们将SQL复制到SSMS中,它只需要大约2秒钟运行,所以这不是问题。 –

相关问题