C# 某些linq2sql生成的T-SQL出现问题

C# 某些linq2sql生成的T-SQL出现问题,c#,sql-server,tsql,linq-to-sql,sql-execution-plan,C#,Sql Server,Tsql,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.Equ

以下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();
在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]
    ))
在SQL studio中运行良好

但是:

在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]))
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')))) 
或者,如果我删除了或存在的部分,它也可以正常工作:

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]))
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')))) 
谢谢
/尼尔斯

您的订单表必须相当大。您在OrderDate上有索引,对吗? 在本例中,SQL Server实际上生成了两种不同的执行计划。或者,如果它生成相同的计划,那么SQL为这两条语句返回的行数会有很大不同

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'
第一条语句生成一个参数化查询,计划优化器将假定@p0在当时是未知的,并选择一个最适合未知值的执行计划。
在第二条语句中,优化器将考虑您提供的固定值。SQL将查看索引分布,并估计将通过>='2013-08-01'过滤多少行。

我的解决方案是重建OrderDate的索引

执行计划不可见,但一般来说,sql性能建议不要使用否定,因为它总是会影响性能。在你的情况下,试着使用=


如果你使用了很多,它也会影响你的表现。尝试使用子查询作为解决方法,以避免使用许多or或否定。

第二个SQL代码中的
'2013-08-01 00:00:00.000'
只是一个字符串,而不是
DateTime
@Tico当与真正的DateTime值比较时,字符串值将转换为DateTime。如果这是不可能的,则会抛出一个错误,并且SQL server应该足够聪明,可以执行一次此强制转换,而不是每行执行一次,因此这不是这里的一个因素。@Niels Bosma查询在SSMS中是否完成过?如果是的话,就值得看一看执行计划。@DrewR 34分钟后是:(.我附上了一个执行计划。不幸的是,我无法在你的屏幕抓图中读取查询计划。另外,你能连续运行34分钟两次,看看每次执行的时间是否改变(思考计划缓存)?实际上order表并没有那么大。只有39998行。是的,OrderDate上有一个非聚集的、非唯一的索引。运行sql时,它返回相同的结果,参数化的结果实际上有更大的子树开销。@NielsBosma是的,这正是您的一个查询超时的原因。查询在功能上是相同的艾尔,但他们的执行方式不同。