2015-04-01 504 views
0

我們有一個REST服務來獲取給定ID的成員。 SQL運行速度很快(5ms),但是從Linq運行(使用Entity framework 6)時,運行非常慢(230ms)。Linq查詢運行緩慢,但查詢運行速度很快

我不是這個問題是this,thisthis的副本,因爲它感覺與Linq/EntityFramework相關。

這裏是統計: 調用成員GET採取客戶端的時間約爲360ms 從C#代碼執行LINQ查詢所需要的時間約爲230ms 執行的SQL的SQL所花費的時間服務器大約是228ms

生產中的SQL跟蹤具有相似的性能(在SQL服務器上執行SQL爲141ms),因此數字感覺真實。

我試着連續六次運行Linq查詢來查看從datacontext建立連接的成本是否成問題。這些Linq查詢中的每一個都花費了相同的時間來運行。

如果我使用相同的datacontext直接運行SQL(即:Linq生成的),運行時(從C#測量)從230ms下降到19ms。

直接在服務器上運行SQL(SQL Server management Studio)大約需要5ms。

C#代碼(都在同一程序中,使用相同的datacontext,沒有使用塊)產生這些數字:

Linq original query run =227ms 
Raw SQL query: 19ms 
Linq run 0=228 
Linq run 1=227 
Linq run 2=229 
Linq run 3=229 
Linq run 4=232 

LINQ查詢看起來像這樣:

DateTime start = DateTime.Now; 
     var memberDetail = await (from member in DataContext.Members.AsNoTracking() 
            join memberName in DataContext.MemberNames.AsNoTracking() on member.UID equals memberName.MemberID into nameOutput 
            from mn in nameOutput.DefaultIfEmpty() 
            join memberProperty in DataContext.Properties.AsNoTracking() on member.PropertyID equals memberProperty.UID 
            join membershipCycle in DataContext.MembershipCycleHistories.AsNoTracking() on member.UID equals membershipCycle.MemberID into cycleOutput 
            from co in cycleOutput.DefaultIfEmpty() 
            where member.ReferenceNumber.Equals(memberNumber) && 
             memberProperty.ExternalID.Equals(property, StringComparison.InvariantCultureIgnoreCase) 
            select new 
            { 
             member.UID, 
             member.Created, 
             member.LastUpdated, 
             PropertyName = memberProperty.ExternalID, 
             member.ReferenceNumber, 
             member.Active, 
             member.IsAwaitingSync, 
             member.Class, 
             mn.FirstName, 
             mn.LastName, 
             mn.PreferredName, 
             MembershipCreditBalance = co.MembershipCredits, 
             member.DOB 
            } 
           ).FirstOrDefaultAsync(); 
     System.Diagnostics.Trace.WriteLine(String.Format("linq run original={0}", (DateTime.Now - start).TotalMilliseconds)); 

和連接字符串是:

Data Source=SQLServer123;Initial Catalog=DB123;Persist Security Info=True;User ID=User123;Password=PWD123;MultipleActiveResultSets=True 
+1

不要使用'DateTime.Now'在500ms以下執行計時,請使用'Stopwatch'類重新運行測試。另外,您是如何獲得原始SQL針對服務器運行的,您是如何運行它的?最後,如果您使用Sql Profiler,linq查詢需要多長時間才能執行服務器端? – 2015-04-02 00:20:18

+0

@ScottChamberlain - 我用秒錶重溫這些。結果在提供的數字的5%以內。 SQL是從linq查詢(tostring())和SQL跟蹤中提取的。直接在management studio中運行查詢的運行時間爲5毫秒。 – dave 2015-04-02 01:08:54

回答

0

經過一點點調查後,我發現了這個問題。數據庫對其所有字符串都使用varchars。當Linq將其參數傳遞給SQL Server時,它將它們作爲Unicode傳遞。 SQL Server查看數據類型並指出它不能使用varchar索引,因此會回到線性掃描。

通過將數據庫從varchar更改爲nvarchar,我的查詢速度從258ms變爲3ms。

+0

在這種情況下,它只是where子句中的參數引起這種情況,還是返回本身也是字符串的行也會導致問題? – Gilles 2016-03-17 15:38:09

+0

@Gilles - 問題是類型不匹配。只要參數匹配實際的數據庫列類型,你應該沒問題。也就是說,.Net將所有字符串作爲unicode傳遞,因此DB字符串列應始終爲nvarchar。 – dave 2016-03-17 23:35:30

+0

如果您無法控制數據庫列的類型,該怎麼辦? – Shavais 2017-02-17 00:52:35

相關問題