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