2015-04-01 236 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

相关问题