说我有这样的查询:
SELECT *
FROM Foo
WHERE Name IN ('name1', 'name2')
AND (Date<'2013-01-01' AND Date>'2010-01-01')
AND Type = 1
有没有办法强制SQL服务器按照我确定的顺序来评估表达式,而不是查询优化器所说的内容?例如,我希望首先评估IN
子句,然后评估Type = 1
评估的输出,最后确定日期,完全按顺序排列。
答案 0 :(得分:5)
是的,这在很大程度上是可能的(虽然有一些警告和反例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
,则防止除以零)。
将谓词包装起来会使查询完全无法查找,并阻止三个(否则为sargable)谓词中的任何一个使用索引。它保证读取所有行的完整扫描。
要查看此
的示例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
答案 1 :(得分:-1)
简答:不!
您可以尝试使用括号,提示,研究查询计划等。
但这样对付引擎/优化器是否明智? 你需要大量的学习和经验才能超越优化器,也就是说,请让引擎为你处理这些细节。