如何优化实体框架查询

问题描述:

我正在使用Linq-To-Entities执行查询,该查询仅返回947行,但需要18秒才能运行。我做了一个“ToTraceString”来获取底层的SQL,并直接在数据库上运行相同的事情并获得相同的时间。如何优化实体框架查询

我已经使用了调整顾问并创建了几个索引,但影响不大。

望着查询执行计划有几个嵌套循环的被占用了95%的时间,但这些都是在指数已经工作?

有没有人有任何想法如何强制一些优化到EF查询?

编辑:提供额外的信息

一个基本ER图的三个表如下:

People >----People_Event_Link ----< Events 
P_ID  P_ID     E_ID 
      E_ID 

,我运行的目的是让所有的活动返回特定人LINQ (使用P_ID):

 var query = from ev in genesisContext.Events 
        join pe in genesisContext.People_Event_Link 
        on ev equals pe.Event 
        where pe.P_ID == key 
        select ev; 
     return query; 

这里是生成的SQL(深呼吸!):

SELECT 
1 AS [C1], 
[Extent1].[E_ID] AS [E_ID], 
[Extent1].[E_START_DATE] AS [E_START_DATE], 
[Extent1].[E_END_DATE] AS [E_END_DATE], 
[Extent1].[E_COMMENTS] AS [E_COMMENTS], 
[Extent1].[E_DATE_ADDED] AS [E_DATE_ADDED], 
[Extent1].[E_RECORDED_BY] AS [E_RECORDED_BY], 
[Extent1].[E_DATE_UPDATED] AS [E_DATE_UPDATED], 
[Extent1].[E_UPDATED_BY] AS [E_UPDATED_BY], 
[Extent1].[ET_ID] AS [ET_ID], 
[Extent1].[L_ID] AS [L_ID] 
FROM [dbo].[Events] AS [Extent1] 
INNER JOIN [dbo].[People_Event_Link] AS [Extent2] ON EXISTS (SELECT 
    1 AS [C1] 
    FROM (SELECT 1 AS X) AS [SingleRowTable1] 
    LEFT OUTER JOIN (SELECT 
     [Extent3].[E_ID] AS [E_ID] 
     FROM [dbo].[Events] AS [Extent3] 
     WHERE [Extent2].[E_ID] = [Extent3].[E_ID]) AS [Project1] ON 1 = 1 
    LEFT OUTER JOIN (SELECT 
     [Extent4].[E_ID] AS [E_ID] 
     FROM [dbo].[Events] AS [Extent4] 
     WHERE [Extent2].[E_ID] = [Extent4].[E_ID]) AS [Project2] ON 1 = 1 
    WHERE ([Extent1].[E_ID] = [Project1].[E_ID]) OR (([Extent1].[E_ID] IS NULL) AND ([Project2].[E_ID] IS NULL)) 
) 
WHERE [Extent2].[P_ID] = 291 
+0

我只是敲了我自己的SQL做查询,它在一秒钟内运行良好,sheesh .... SELECT * FROM Events AS E INNER JOIN People_Event_Link AS PE ON E.E_ID = PE。 E_ID INNER JOIN PEOPLE作为P.P_ID = PE.P_ID其中P.P_ID = 291 – Calanus 2009-08-05 15:35:44

是的。重写LINQ查询。大多数LINQ to Entities查询可以用许多不同的方式编写,并且将以不同的方式转换为SQL。既然你既不显示LINQ,也不显示SQL或查询计划,这就是我所能说的。

尽管如此,您仍然很聪明,可以直接尝试执行SQL。查询编译也可能需要时间,但是您已经通过确定SQL计算了所有测量时间来排除此问题。

尝试:

var query = from pe in genesisContext.People_Event_Link 
       where pe.P_ID == key 
       from ev in pe.Event // presuming one to many 
       select ev; 

,或者如果pe.Event是一对一的:时间

var query = from pe in genesisContext.People_Event_Link 
       where pe.P_ID == key 
       select pe.Event; 

    return query; 
+0

嗯,我已经看了一下linq查询,但说实话,它并没有太多的改变(见上文)! – Calanus 2009-08-05 15:16:47

+2

在LINQ to Entities中使用连接几乎是不对的。什么是People_Event_Link的事件上的属性名称(换句话说,pe.Event的另一端?我会在我的答案中猜测;如果我错了,请纠正我。 – 2009-08-05 16:00:19

+0

请参阅下面的“答案” - 不能将代码放在注释中: - \ – Calanus 2009-08-06 10:08:26

因为95%是在嵌套循环,消除它们应该解决的问题。

有几件事情,你可以看看:

  • 是必要的嵌套循环。如果您直接在SQL中编写查询,则可以在不使用嵌套循环的情况下得到相同的结果。如果对此的回答是它可以在没有嵌套循环的情况下编写,那么在模型或linq查询中导致它的是什么。

  • 是否可以选择在视图中放置一些逻辑,从而降低linq查询的复杂性,并且可能不需要嵌套循环。

正常情况下,我使用SQL服务器分析器来查看SQL linq产生什么,我觉得这更容易,尤其是如果您有两个屏幕。

如果您仍有问题,请发布您的linq查询。

@Craig 我无法让您的查询工作,因为我收到一条错误消息,指出在SelectMany调用中类型推断失败。

但是我把你的建议和使用的加入到“奥尔德式”预ANSI类型的查询去:

 var query = from pe in genesisContext.People_Event_Link 
        from ev in genesisContext.Events 
        where pe.P_ID == key && pe.Event == ev 
        select ev; 

将会产生相当体面的SQL!

+0

“SelectMany调用失败”意味着我猜错了关于属性名称的问题,但您已经有了一般想法 - 要获得不同的SQL,请尝试使用不同的LINQ。 – 2009-08-06 12:38:32