entity framework查询速度慢,但SqlQuery中的相同的SQL很快
我看到一些非常简单的查询使用entity framework代码优先与.NET框架版本4一些非常奇怪的性能。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,所得到的实体在两种情况下都被更改跟踪,但是两者之间的性能差异很大。 是什么赋予了?
find了。 事实certificate,这是一个SQL数据types的问题。 数据库中的SomeStringProp
列是一个varchar,但EF假定.NETstringtypes是nvarchar。 在查询数据库进行比较过程中产生的翻译过程需要很长时间。 我认为EF Prof在这里让我误入歧途,对查询运行的更精确的描述如下:
SELECT [Extent1].[ID], [Extent1].[SomeStringProp], [Extent1].[SomeOtherProp], ... FROM [MyTable] as [Extent1] WHERE [Extent1].[SomeStringProp] = N'1234567890'
所以最终的解决scheme是注释代码优先模型,指出正确的SQL数据types:
public class MyTable { ... [Column(TypeName="varchar")] public string SomeStringProp { get; set; } ... }
减慢我在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中的一个错误。
如果您使用stream畅的映射,您可以使用IsUnicode(false)
作为configuration的一部分,以获得相同的效果 –
http://msdn.microsoft.com/en-us/data/jj591617.aspx#1.9
http://msdn.microsoft.com/en-us/library/gg696416%28v=vs.103%29.aspx
我有同样的问题(从SQLpipe理器执行查询是快速的),但从EF执行超时过期。
原来那个实体(它是从视图中创build的)具有错误的实体键。 所以实体有相同的键重复的行,我想它不得不在背景上进行分组。
我也遇到了一个复杂的查询。 一个修复程序,减less了6秒的查询,以生成它的第二个SQL查询是closures延迟加载。
要find此设置(例如6),请转到.edmx文件并查看属性 – >代码生成 – >延迟加载启用。 设置为false。
对我来说,性能的大幅提高。
您可以使用以下技巧来加快查询速度 –
- 在获取上下文之前将
ctx.Configuration.ProxyCreationEnabled
设置为false
。 - 此外,
.Select(c => new {c.someproperty})
将只提取所需的数据,而不是整个一堆。
让我知道这是否有帮助。