EntityFramework LINQToEntities生成奇怪缓慢的TSQL Where子句。

7
我需要理解这个。 在TSQL代码生成方面,EF5.0和EF6.*之间存在很大的差异。
在我的代码中,这是我的LINQ语句。
var qry2 = context.viw_overview_1.Where(i => i.article_EAN17 == ean).Select(i => i.article_id).Take(200);

EntityFramework 5.0 生成了一个简单快速的 TSQL WHERE 语句,像这样的语句是完美的。
... WHERE [Extent1].[article_EAN17] = @p__linq__0
00.0960096ms in SSMS

但是EntityFramework 6.*生成的语句更加复杂和缓慢。
... WHERE (([Extent1].[article_EAN17] = @p__linq__0) AND ( NOT ([Extent1].[article_EAN17] IS NULL OR @p__linq__0 IS NULL))) OR (([Extent1].[article_EAN17] IS NULL) AND (@p__linq__0 IS NULL))
45.3665362ms in SSMS

该字段“article_EAN17”也有索引。 然而,EF6.*初始化需要很长时间,但是是否有一种方法在EF6.*中生成一个简单的WHERE语句,使用属性或类似的东西? 我尝试了string.Equals()、string.Compare(),交换参数,但什么也没改变。 这篇文章为什么Entity Framework 6为简单查找生成复杂的SQL查询?解释了差异,但是否有一种方法可以强制EF生成简单的TSQL。

1
我怀疑 T-SQL 的更改是否会减慢速度。你是否尝试在相同的数据集上运行这两个查询? - haim770
1
只是好奇 - 你是否将这两个语句放入SSMS中并比较它们的性能? - Eric Scherrer
EF5的简单比较在C#中比EF6快5倍,在SSMS中则更快。 - Roland
2
EF 的美妙之处在于你不需要过多关注这些事情,或者只需要稍微关注一下——否则,泄漏的抽象会让整个项目陷入困境。除了一些高级的控制方式,比如使用 .Include 或 .AsNoTracking,如果你有性能要求需要精确控制 SQL 的使用,那么可以考虑使用存储过程。 - Eric Scherrer
另一个想法是,article_EAN17是否可为空是因为外连接还是因为它是数据库中的可空列?如果是后者,也许您可以不允许该列为空值? - Eric Scherrer
2
这个没被覆盖到吗?https://entityframework.codeplex.com/workitem/145 - MattC
2个回答

8
我认为这与Entity Framework中的NULL比较设置有关。在查询之前添加以下代码,以查看是否可以提高查询性能:
context.ContextOptions.UseCSharpNullComparisonBehavior = true;

1
默认不是false吗?http://msdn.microsoft.com/zh-cn/library/system.data.entity.core.objects.objectcontextoptions.usecsharpnullcomparisonbehavior(v=vs.113).aspx - Corey Adler
3
实际上,这是 context.Configuration.UseDatabaseNullSemantics = true;,感谢 MattC。 - Roland

1
如果您绝对、肯定需要将添加的空值检查去掉,您可以始终使用 DbSet.SqlQuery() (文档 在这里)手动配置您想要运行的查询(以及所有参数)。不过要小心,因为有时该方法可能会以您意想不到的方式工作。如果您不想/不需要任何跟踪,您也可以使用 Database.SqlQuery<T>() (文档 在这里),这将允许您在查询中使用泛型(否则您将不得不进行强制转换)。
个人而言,我更愿意不做任何修改,或者像@EricScherrer在评论中提到的那样使用存储过程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接