我正在执行以下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))
PartsRouting Table有100,000多条记录,Parts = 15000 +,Processes = 200。
我尝试了太多在线发现的东西,但对于我如何以相同的SQL性能实现结果没有任何作用。
答案 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();