2009-08-05 117 views
4

我正在使用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

回答

4

是的。重寫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

1

因爲95%是在嵌套循環,消除它們應該解決的問題。

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

  • 是必要的嵌套循環。如果您直接在SQL中編寫查詢,則可以在不使用嵌套循環的情況下得到相同的結果。如果對此的回答是它可以在沒有嵌套循環的情況下編寫,那麼在模型或linq查詢中導致它的是什麼。

  • 是否可以選擇在視圖中放置一些邏輯,從而降低linq查詢的複雜性,並且可能不需要嵌套循環。

正常情況下,我使用SQL服務器分析器來查看SQL linq產生什麼,我覺得這更容易,尤其是如果您有兩個屏幕。

如果您仍有問題,請發佈您的linq查詢。

1

@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