Sql server 确定查询中的操作顺序
假设我有这样一个问题:Sql server 确定查询中的操作顺序,sql-server,sql-server-2008,tsql,Sql Server,Sql Server 2008,Tsql,假设我有这样一个问题: SELECT * FROM Foo WHERE Name IN ('name1', 'name2') AND (Date<'2013-01-01' AND Date>'2010-01-01') AND Type = 1 选择* 来自富 其中名称位于('name1','name2') 和(日期'2010-01-01') 和类型=1 有没有办法强制SQL server按照我确定的顺序计算表达式,而不是按照查询优化器所说的顺序计算?例如,我希望先计
SELECT *
FROM Foo
WHERE Name IN ('name1', 'name2')
AND (Date<'2013-01-01' AND Date>'2010-01-01')
AND Type = 1
选择*
来自富
其中名称位于('name1','name2')
和(日期'2010-01-01')
和类型=1
有没有办法强制SQL server按照我确定的顺序计算表达式,而不是按照查询优化器所说的顺序计算?例如,我希望先计算IN
子句中的,然后按Type=1
计算该子句的输出,最后是日期,顺序完全相同。简短回答:否
您可以尝试使用括号、提示、研究查询计划等
但这样搞砸引擎/优化器明智吗?
您需要大量的研究和经验才能胜过优化器,也就是说,请让引擎为您处理这些细节。是的,这在很大程度上是可能的(尽管有一些警告和反例)
然后运行问题中的原始查询vs此查询将给出计划
注意,第二个查询的成本是批次成本的100%
留给自己设备的查询优化器首先查找与类型
谓词匹配的414行,并将其用作哈希表的构建输入。然后,它搜索与名称
匹配的728行,查看它是否与哈希表中的任何内容匹配,对于匹配的4行,它对其他列执行键查找,并根据这些列计算日期
谓词。最后,它返回单个匹配行
第二个查询只是遍历表中的所有行,并按所需顺序计算谓词。阅读页数的差异非常显著
原始查询
嵌套格
为什么谓词的求值顺序很重要?true和true,true总是求值为true。为什么您认为强制SQL Server按特定顺序评估真理会给您带来任何好处?优化器很聪明。你不能骗他做傻事。试图智胜优化器通常不是一个好主意。如果你的问题是效率,这不是提问的方式。尝试添加表定义、所有索引和慢查询的实际执行计划。SQL Server的优化器只是迟钝了。@BARM-Intersect
不能保证与此相关的任何东西。@MartinSmith同意。我只看到了按查询顺序排列的Intersect,但我玩了一下,得到了一些查询计划,而不是按查询顺序排列的。即使更改查询计划也很棘手,需要了解引擎如何解析和执行。此外,你还需要了解提示等。马丁发布了一个“工作”的方式。答案是+1。这确保了每一行的执行顺序(如您所说,并附带一些注意事项)。我们还可以使用临时表,在表级别强制执行此操作(首先检查
条件中的,在temp1保存,然后检查…在temp2保存,…)@ypercube-另外,在所有情况下,“求值顺序”的含义并不明确。e、 g.在第一个计划中,它使用匹配的type
计算行,然后计算匹配的行。所以从某种意义上说,它首先评估了这一点。但是它会返回seek中所有匹配的name
行,而不仅仅是那些已经被证明与类型匹配的行。谢谢你给出了一个好的答案,但是我通过将谓词移到连接条件来解决了我的特殊情况,然后我能够通过使用连接提示强制执行顺序。查询运行时间从2分钟变为2秒。
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
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
Table 'Foo'. Scan count 3, logical reads 23,
Table 'Worktable'. Scan count 0, logical reads 0
Table 'Foo'. Scan count 1, logical reads 100373