是的,这在很大程度上是可能的(尽管有一些警告和反例discussed in the answers here)
SELECT *
FROM Foo
WHERE 1 = CASE
WHEN Name IN ( 'name1', 'name2' ) THEN
CASE
WHEN Type = 1 THEN
CASE
WHEN ( Date < '2013-01-01'
AND Date > '2010-01-01' ) THEN 1
END
END
END
但是为什么要打扰呢?只有在非常有限的情况下,我认为这会很有用(例如,如果早期的谓词评估为 0,则防止除以零)。
像这样包装谓词会使查询完全不可分割,并防止三个(否则可分割的)谓词中的任何一个使用索引。它保证读取所有行的全扫描。
看一个例子
CREATE TABLE Foo
(
Id INT IDENTITY PRIMARY KEY,
Name VARCHAR(10),
[Date] DATE,
[Type] TINYINT,
Filler CHAR(8000) NULL
)
CREATE NONCLUSTERED INDEX IX_Name
ON Foo(Name)
CREATE NONCLUSTERED INDEX IX_Date
ON Foo(Date)
CREATE NONCLUSTERED INDEX IX_Type
ON Foo(Type)
INSERT INTO Foo
(Name,
[Date],
[Type])
SELECT TOP (100000) 'name' + CAST(0 + CRYPT_GEN_RANDOM(1) AS VARCHAR),
DATEADD(DAY, 7 * CRYPT_GEN_RANDOM(1), '2012-01-01'),
0 + CRYPT_GEN_RANDOM(1)
FROM master..spt_values v1,
master..spt_values v2
然后在问题中运行原始查询与此查询给出计划
请注意,第二个查询的成本是批处理成本的 100%。
留给自己设备的查询优化器首先查找与 type 谓词匹配的 414 行,并将其用作哈希表的构建输入。然后它查找与name 匹配的728 行,查看它是否匹配哈希表中的任何内容,并且对于匹配的4 行,它对其他列执行键查找并针对这些列评估Date 谓词。最后它返回单个匹配行。
第二个查询只是遍历表中的所有行并以所需的顺序评估谓词。阅读页数的差异非常显着。
原始查询
Table 'Foo'. Scan count 3, logical reads 23,
Table 'Worktable'. Scan count 0, logical reads 0
嵌套案例
Table 'Foo'. Scan count 1, logical reads 100373