3

对于以下 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 工作室中运行良好!

但:

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]))

并且会在 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]))

或者,如果我删除 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')))) 

谢谢/尼尔斯

4

3 回答 3

5

您的 Orders 表必须相当大。您在 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'

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

于 2013-11-13T22:18:24.930 回答
3

执行计划是不可见的,但一般 sql 性能建议不要使用否定它总是会影响性能。在您的情况下,尝试使用 <= 代替否定与 >=

如果你使用很多,否则它也会影响你的表现。尝试使用子查询来解决不使用许多或或否定的方法。

于 2013-11-15T19:17:59.723 回答
2

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

于 2013-11-14T13:30:16.057 回答