【问题标题】:SQL Server: Subquery in "boolean" WHERE clauseSQL Server:“布尔”WHERE 子句中的子查询
【发布时间】:2014-11-04 20:25:48
【问题描述】:

我有使用以下构造的 T-SQL 查询 (SQL Server 2008/2012):

WHERE (@param1 IS NULL OR column1 = @param1)
AND (@param2 IS NULL OR column2 = @param2)
AND (@param3 IS NULL OR column3 = @param3)

这可以正常工作,并使用 NULL 参数自动优化 WHERE 子句的任何 AND 部分。

但是当我对子查询做同样的事情时,即使参数为 NULL,优化器似乎仍会执行子查询:

WHERE 
    (@param1 IS NULL OR column1 IN (SELECT column 
                                    FROM table 
                                    WHERE column = @param1))
    AND (@param2 IS NULL OR column2 IN (SELECT column 
                                        FROM table 
                                        WHERE column = @param2))
    AND (@param3 IS NULL OR column3 IN (SELECT column 
                                        FROM table 
                                        WHERE column = @param3))

我的问题是,为什么优化器甚至会考虑“IN”SELECT,因为参数为 NULL 的事实应该已经“短路”了查询的那部分?

【问题讨论】:

  • 据我所知,SQL Server 中没有short circuit。您需要使用CASE 来实现short circuit 行为
  • 阅读我的this answer 了解 CASE 的使用示例
  • @cha:我非常有信心第一个代码示例按预期工作;这不是我发明的,但我已经使用了一段时间,执行计划证明了预期的行为。第二个代码示例也可以,但执行计划显示子查询仍在执行中。
  • @user640466 。 . .是什么让您认为第一个查询对 or 子句做了任何优化?
  • @GordonLinoff:查看执行计划以及根据哪些参数是否为 NULL 来确认查询中使用了哪些索引;这是对这种结构的众多引用之一:weblogs.sqlteam.com/jeffs/archive/2007/09/18/…

标签: sql sql-server tsql subquery where-in


【解决方案1】:

@user640466:我认为如果您添加 OPTION (RECOMPILE) 查询提示,错误的计划将会消失,原因是查询优化器必须评估 IN 子句以获取 ProductID 值,而在 OPTION(重新编译)的情况下它可以嗅探运行时值。请参阅下面 Adventure 作品的工作副本:

CREATE PROC MyTest
@ProductID INT ,
@Name NVARCHAR(50),
@ProductNumber NVARCHAR(50)
AS
SELECT * 
FROM Production.Product 
WHERE 
(ProductID IN (SELECT ProductID FROM Production.Product WHERE ProductID = @ProductID ) OR @ProductID IS NULL)
AND 
(Name IN (SELECT Name FROm Production.Product WHERE Name = @Name) OR @Name IS NULL)
AND 
(ProductNumber IN (SELECT ProductNumber FROM Production.Product WHERE ProductNumber = @ProductNumber)  OR @ProductNumber IS NULL)
--OPTION (RECOMPILE)
GO 

如果你执行 Proc : EXEC Mytest 1,NULL,NULL 你会得到一个冗长的计划但是改变 sp 并取消注释 OPTION (RECOMPILE) 你会得到一个不错的计划。

【讨论】:

  • 我会对此进行试验,但即便如此,优化器似乎可以轻松避免子查询,即使没有重新编译;如果 OR 逻辑使子查询的结果无关紧要,为什么还要执行子查询?
猜你喜欢
  • 2021-10-14
  • 1970-01-01
  • 1970-01-01
  • 2015-03-29
  • 2011-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多