Nie*_*sma 3 c# t-sql sql-server linq-to-sql sql-execution-plan
对于以下LINQ2SQL查询,我遇到SQL超时问题:
DateTime date = DateTime.Parse("2013-08-01 00:00:00.000");
Clients.Where(e =>
(
!Orders.Any(f => f.ClientId.Equals(e.Id) && f.OrderDate >= date)
||
Comments.Any(f => f.KeyId.Equals(e.Id))
)
).Count().Dump();
Run Code Online (Sandbox Code Playgroud)
在LinqPad中运行它时,将需要永远完成,如果在服务器上运行,将成为SQL超时.
生成的SQL代码:
-- Region Parameters
DECLARE @p0 DateTime = '2013-08-01 00:00:00.000'
-- EndRegion
SELECT COUNT(*) AS [value]
FROM [Clients] AS [t0]
WHERE (NOT (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Orders] AS [t1]
WHERE ([t1].[ClientId] = [t0].[Id]) AND ([t1].[OrderDate] >= @p0)
))) OR (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Comments] AS [t2]
WHERE [t2].[KeyId] = [t0].[Id]
))
Run Code Online (Sandbox Code Playgroud)
在SQL-studio中正常工作!
但:
SELECT COUNT(*) AS [value]
FROM [Clients] AS [t0]
WHERE
(NOT (EXISTS(SELECT NULL AS [EMPTY] FROM [Orders] AS [t1] WHERE ([t1].[ClientId] = [t0].[Id]) AND ([t1].[OrderDate] >= '2013-08-01 00:00:00.000'))))
OR
(EXISTS(SELECT NULL AS [EMPTY] FROM [Comments] AS [t2] WHERE [t2].[KeyId] = [t0].[Id]))
Run Code Online (Sandbox Code Playgroud)
并且会在LinqPad中实际运行查询时遇到问题.
DECLARE @p0 DateTime = '2013-08-01 00:00:00.000'与使用常量日期相比,使用有什么区别?如何让我的Linq2SQL工作?
编辑:
查看两个查询的执行计划:
超时:

精细:

我注意到的其他一些事情是,如果我删除NOT它工作正常:
SELECT COUNT(*) AS [value]
FROM [Clients] AS [t0]
WHERE
((EXISTS(SELECT NULL AS [EMPTY] FROM [Orders] AS [t1] WHERE ([t1].[ClientId] = [t0].[Id]) AND ([t1].[OrderDate] >= '2013-08-01 00:00:00.000'))))
OR
(EXISTS(SELECT NULL AS [EMPTY] FROM [Comments] AS [t2] WHERE [t2].[KeyId] = [t0].[Id]))
Run Code Online (Sandbox Code Playgroud)
或者,如果我删除OR EXISTS部件,它也可以正常工作:
SELECT COUNT(*) AS [value]
FROM [Clients] AS [t0]
WHERE
((EXISTS(SELECT NULL AS [EMPTY] FROM [Orders] AS [t1] WHERE ([t1].[ClientId] = [t0].[Id]) AND ([t1].[OrderDate] >= '2013-08-01 00:00:00.000'))))
Run Code Online (Sandbox Code Playgroud)
谢谢/尼尔斯
小智 5
您的订单表必须相当大.您有OrderDate的索引吗?在此示例中,SQL Server实际上生成了2个不同的执行计划.或者,如果它生成相同的计划,则SQL为2个语句提供了大大不同的返回行数.
DECLARE @p0 DateTime = '2013-08-01 00:00:00.000'
SELECT * FROM Orders WHERE OrderDate >= @p0
SELECT * FROM Orders WHERE OrderDate >= '2013-08-01 00:00:00.000'
Run Code Online (Sandbox Code Playgroud)
第一个语句生成参数化查询,计划优化器将假设@ p0当时未知,并选择最适合未知值的执行计划.第二个语句,优化器将考虑您提供的固定值.SQL将查看索引分布并估计将通过> ='2013-08-01'过滤的行数