实体框架LINQ to Entities加入查询超时

时间:2017-03-23 10:24:03

标签: c# sql-server entity-framework linq

我正在执行以下LINQ to Entities查询,但它被卡住了,直到超时才返回响应。我在SQL Server上执行了相同的查询,并在3秒内返回92000。

            var query = (from r in WinCtx.PartsRoutings
                     join s in WinCtx.Tab_Processes on r.ProcessName equals s.ProcessName
                     join p in WinCtx.Tab_Parts on r.CustPartNum equals p.CustPartNum
                     select new { r}).ToList();

SQL Generated:

SELECT [ I omitted columns]
    FROM   [dbo].[PartsRouting] AS [Extent1]
INNER JOIN [dbo].[Tab_Processes] AS [Extent2] ON ([Extent1].[ProcessName] = [Extent2].[ProcessName]) OR (([Extent1].[ProcessName] IS NULL) AND ([Extent2].[ProcessName] IS NULL))
INNER JOIN [dbo].[Tab_Parts] AS [Extent3] ON ([Extent1].[CustPartNum] = [Extent3].[CustPartNum]) OR (([Extent1].[CustPartNum] IS NULL) AND ([Extent3].[CustPartNum] IS NULL))

PartsRou​​ting Table有100,000多条记录,Parts = 15000 +,Processes = 200。

我尝试了太多在线发现的东西,但对于我如何以相同的SQL性能实现结果没有任何作用。

1 个答案:

答案 0 :(得分:5)

根据评论,看起来问题是由EF SQL转换器生成的连接中的OR附加IS NULL条件引起的。它们是在EF中添加的,以便模拟C#==运算符语义,这些语义与=值的SQL NULL不同。

您可以首先通过UseDatabaseNullSemantics属性关闭EF行为(默认情况下为false):

WinCtx.Configuration.UseDatabaseNullSemantics = true;

不幸的是,这还不够,因为它修复了正常的比较运算符,但是他们只是忘了对连接条件做同样的事情。

如果你只是为了过滤而使用连接(看起来如此),你可以用LINQ Any条件替换它们,这些条件转换为SQL EXISTS,现在数据库查询优化器正在以同样的方式处理它就好像它是一个内部联接:

var query = (from r in WinCtx.PartsRoutings
             where WinCtx.Tab_Processes.Any(s => r.ProcessName == s.ProcessName)
             where WinCtx.Tab_Parts.Any(p => r.CustPartNum == p.CustPartNum)
             select new { r }).ToList();

您可能还会考虑仅使用select r,因为使用单个属性创建匿名类型只会增加额外的内存开销而没有任何优势。

更新:查看最新评论,您执行需要来自联接表的字段(这就是为什么不要忽略相关查询的相关部分很重要)。在这种情况下,您可以尝试使用where子句的替代连接语法:

WinCtx.Configuration.UseDatabaseNullSemantics = true;
var query = (from r in WinCtx.PartsRoutings
             from s in WinCtx.Tab_Processes where r.ProcessName == s.ProcessName
             from p in WinCtx.Tab_Parts where r.CustPartNum == p.CustPartNum
             select new { r, s.Foo, p.Bar }).ToList();