2013-04-02 190 views
55

我看到一些非常奇怪的性能問題,與使用實體框架代碼優先的.NET框架版本4進行的非常簡單的查詢有關.LINQ2Entities查詢如下所示:實體框架查詢速度慢,但SqlQuery中的SQL相同速度很快

context.MyTables.Where(m => m.SomeStringProp == stringVar); 

這需要超過3000毫秒的時間才能執行。生成的SQL看起來非常簡單:

SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp], 
... 
FROM [MyTable] as [Extent1] 
WHERE [Extent1].[SomeStringProp] = '1234567890' 

此查詢在運行Management Studio時幾乎同時運行。當我改變了C#代碼使用sqlquery函數,它運行在5-10毫秒:

context.MyTables.SqlQuery("SELECT [Extent1].[ID] ... WHERE [Extent1].[SomeStringProp] = @param", stringVar); 

因此,完全相同的SQL,生成的實體變化跟蹤在這兩種情況下,但之間的野生PERF差異二。是什麼賦予了?

+2

我希望你看到初始化延遲 - 可能查看編譯。請參閱MSDN:[「實體框架5的性能注意事項」](http://msdn.microsoft.com/zh-cn/data/hh949853.aspx) –

+0

我試過預生成的視圖,但它似乎沒有幫助。另外,在慢速之前運行另一個EF查詢以排除初始化內容。儘管在第一次查詢期間發生了上下文預熱,但新查詢很快運行,緩慢運行仍然緩慢運行。 –

+0

@marc_s - 不,SqlQuery將返回一個完全物化和變化跟蹤的實體實例。請參閱http://msdn.microsoft.com/en-us/library/system.data.entity.dbset.sqlquery(v=vs.103).aspx –

回答

57

找到它。事實證明這是一個SQL數據類型的問題。數據庫中的SomeStringProp列是varchar,但EF假定.NET字符串類型是nvarchars。在查詢數據庫進行比較期間產生的翻譯過程需要很長時間。我認爲EF教授帶領我誤入歧途了一下這裏,查詢更精確地表示正在運行的將是如下:

SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp], 
... 
FROM [MyTable] as [Extent1] 
WHERE [Extent1].[SomeStringProp] = N'1234567890' 

所以,最終的解決辦法是註釋代碼第一種模式,指示正確的SQL數據類型:

public class MyTable 
{ 
    ... 

    [Column(TypeName="varchar")] 
    public string SomeStringProp { get; set; } 

    ... 
} 
+0

很好的調查。您的查詢遭受了「隱式轉換」的困擾,正如這裏所解釋的:http://www.brentozar.com/archive/2012/07/identifying-correcting-sql-server-implicit-conversion/ – Jaime

+0

爲我節省了幾個小時的調試。這正是問題所在。 – Cody

+0

偉大的人!現在我的程序快20倍! –

2

我有同樣的問題,但是從EF執行超時到期時(從SQL經理執行時查詢速度快)。

原來,實體(它是從視圖創建的)具有錯誤的實體鍵。所以實體有相同的鍵重複的行,我想它必須在背景上進行分組。

1

我也碰到這個帶着複雜查詢。 對我來說,一個修復程序減少了6秒鐘的查詢次數,使其生成的第二個sql查詢是關閉延遲加載。

要找到此設置(例如6),請轉到.edmx文件並查看Properties - > Code generation - > Lazy Loading Enabled。設置爲false。

對我來說,性能的巨大提高。

+3

這很酷,但與海報問題無關。 –

25

拖慢我在EF進行的查詢的原因是比較不可空的標量可空標量:

long? userId = 10; // nullable scalar 

db.Table<Document>().Where(x => x.User.Id == userId).ToList() // or userId.Value 
           ^^^^^^^^^ ^^^^^^ 
           Type: long Type: long? 

該查詢花了35秒。但是像這樣的一個小重構:

long? userId = 10; 
long userIdValue = userId.Value; // I've done that only for the presentation pursposes 

db.Table<Document>().Where(x => x.User.Id == userIdValue).ToList() 
           ^^^^^^^^^ ^^^^^^^^^^^ 
           Type: long Type: long 

給出令人難以置信的結果。它只用了50毫秒就完成了。這可能是EF中的一個錯誤。

+4

這太奇怪了 –

1

您可以使用下面的技巧來繫好查詢 -

  1. 設置ctx.Configuration.ProxyCreationEnabledfalse你獲得上下文權利之前。
  2. 此外,.Select(c => new {c.someproperty})將只提取所需的數據,而不是整個一堆。

讓我知道這是否有幫助。

0

我也有這個問題。事實證明,在我的情況下,罪魁禍首是SQL服務器參數嗅探。 Read more

第一條線索是我的問題,其實是由於參數嗅探是運行與「SET ARITHABORT關閉」或Management Studio中取得了顯着不同的執行時間「上設置ARITHABORT」查詢。這是因爲默認情況下,ADO.NET使用「set arithabort off」,Management Studio默認爲「set arithabort on」,查詢計劃緩存根據此參數保留不同的計劃。

我禁用查詢計劃緩存查詢,解決方案,您可以找到here

相關問題