WHERE子句在IN和JOIN之前或之后更好地执行

时间:2011-03-28 18:03:29

标签: sql-server

我读过这篇文章: Logical Processing Order of the SELECT statement

在文章的最后已经写了ON和JOIN子句在WHERE之前考虑。

考虑一下我们有一个拥有10百万记录的主表和一个具有50百万记录的详细信息表(引用主表(FK))。我们有一个查询,根据PK中只有100条记录的详细信息表主表。

在这种情况下ON和JOIN在WHERE之前执行?我的意思是我们在JOIN之后有500百万条记录然后WHERE适用于它吗?或者首先应用WHERE然后JOIN和ON考虑?如果第二个答案是真的那么它有吗?与顶级文章不一致?

感谢

5 个答案:

答案 0 :(得分:22)

对于INNER JOIN或LEFT JOIN左侧的表,在许多情况下,优化器会发现在实际执行任何类型的物理连接之前,最好先执行任何过滤(最高选择性) - 所以显然有更好的物理操作顺序。

在某种程度上,您有时可以使用SQL来控制(或干扰此),例如,使用子查询中的聚合。

处理查询中约束的逻辑顺序只能根据已知的不变变换进行转换。

所以:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
WHERE a.something = something
    AND b.something = something

在逻辑上仍然等同于:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something

他们通常会有相同的执行计划。

另一方面:

SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
WHERE a.something = something
    AND b.something = something

不等同于:

SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something

因此优化器不会将它们转换为相同的执行计划。

优化器非常智能,能够非常成功地移动它,包括折叠视图和内联表值函数,甚至可以相当成功地通过某些类型的聚合来推送。

通常,当您编写SQL时,它需要是可理解的,可维护的和正确的。就执行效率而言,如果优化器难以将声明性SQL转换为具有可接受性能的执行计划,则有时可以简化代码或将适当的索引或提示添加或分解为应该表现得更快 - 所有这些都是连续的侵入性命令。

答案 1 :(得分:21)

没关系

始终遵循逻辑处理顺序:无论实际处理顺序如何

INNER JOIN和WHERE条件实际上是关联和可交换的(因此ANSI-89“加入where”语法)所以实际顺序无关紧要

对于外连接和更复杂的查询,逻辑顺序变得很重要:在OUTER表上应用WHERE会完全更改逻辑。

同样,只要通过遵循逻辑处理顺序维护查询语义,优化器如何在内部执行它并不重要。

这里的关键词是“优化者”:它完全符合它所说的

答案 2 :(得分:9)

重新阅读Paul White的excellent series on the Query Optimiser并记住这个问题。

可以使用未记录的命令来禁用特定的转换规则,并深入了解所应用的转换。

对于(希望!)显而易见的原因只在开发实例上尝试此操作并记住重新启用它们并从缓存中删除任何次优计划。

USE AdventureWorks2008;

/*Disable the rules*/
DBCC RULEOFF ('SELonJN');
DBCC RULEOFF ('BuildSpool');


 SELECT  P.ProductNumber, 
         P.ProductID, 
        I.Quantity
 FROM    Production.Product P
 JOIN    Production.ProductInventory I
         ON  I.ProductID = P.ProductID
WHERE I.ProductID < 3
OPTION (RECOMPILE)

您可以看到禁用这两个规则后,它会执行笛卡尔连接并在之后进行过滤。

Rules Off Plan

/*Re-enable them*/   
DBCC RULEON ('SELonJN');
DBCC RULEON ('BuildSpool');

 SELECT  P.ProductNumber, 
         P.ProductID, 
        I.Quantity
 FROM    Production.Product P
 JOIN    Production.ProductInventory I
         ON  I.ProductID = P.ProductID
WHERE I.ProductID < 3
OPTION (RECOMPILE)

启用它们后,谓词将被向下推入索引查找,从而减少连接操作处理的行数。

Rules on Plan

答案 3 :(得分:6)

没有明确的订单。 SQL引擎根据优化程序选择的执行策略确定执行操作的顺序。

答案 4 :(得分:2)

我认为您在文章中误读ONIN

但是,它在文章中显示的顺序是正确的(显然它仍然是msdn)。 ONJOIN自然会在WHERE之前执行,因为WHERE必须作为过滤器应用于JOINS

获得的临时结果集

文章只是说它是执行的逻辑顺序,并且在段落的末尾也添加了这一行;)

“请注意,语句的实际物理执行由查询处理器决定,订单可能与此列表不同。”