实体框架查询速度慢,但SqlQuery中的SQL速度相同

时间:2013-04-02 15:16:13

标签: performance entity-framework ef-code-first

我看到一些与使用.NET框架版本4的Entity Framework Code-First的非常简单的查询相关的一些非常奇怪的性能.LINQ2Entities查询如下所示:

 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,在两种情况下都会对结果实体进行更改跟踪,但两者之间存在差异。是什么给了什么?

7 个答案:

答案 0 :(得分:74)

找到它。事实证明这是SQL数据类型的问题。数据库中的SomeStringProp列是varchar,但EF假定.NET字符串类型是nvarchars。在查询DB以进行比较期间产生的转换过程需要很长时间。我认为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; }

    ...
}

答案 1 :(得分:33)

放慢我在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

给出了令人难以置信的结果。完成只用了50ms。它可能是EF中的一个错误。

答案 2 :(得分:7)

如果您正在使用流畅的映射,则可以使用IsUnicode(false)作为配置的一部分来获得相同的效果 -

http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.9

http://msdn.microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx

答案 3 :(得分:3)

我遇到了同样的问题(从SQL管理器执行时查询速度很快)但是从EF执行时超时到期。

事实证明,实体(从视图创建)具有错误的实体键。因此,实体具有相同键的重复行,我猜它必须在后台进行分组。

答案 4 :(得分:2)

我也遇到了一个复杂的ef查询。 对我来说,一个修复程序减少了6秒ef查询到它生成的第二个sql查询是关闭延迟加载。

要查找此设置(ef 6),请转到.edmx文件并查看属性 - &gt;代码生成 - &gt;延迟加载已启用。设置为false。

我的表现大幅提升。

答案 5 :(得分:1)

您可以使用以下技巧来强制查询 -

  1. 在获得上下文之前,将ctx.Configuration.ProxyCreationEnabled设置为false
  2. 此外,.Select(c => new {c.someproperty})只会获取所需的数据,而不是整个数据集。
  3. 如果这有帮助,请告诉我。

答案 6 :(得分:1)

我也有这个问题。事实证明,我的案例中的罪魁祸首是SQL-Server parameter sniffing

我的问题实际上是由于参数嗅探而产生的第一个线索是运行查询&#34;设置arithabort off&#34;或者&#34;设置arithabort on&#34;在Management Studio中产生了截然不同的执行时间。这是因为ADO.NET默认使用&#34; set arithabort off&#34;和Management Studio默认为&#34;设置arithabort on&#34;。查询计划缓存根据此参数保留不同的计划。

我为查询禁用了查询计划缓存,您可以使用here找到解决方案。