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

Ari*_*ian 27 sql-server

我读了这篇文章: SELECT语句的逻辑处理顺序

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

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

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

谢谢

Cad*_*oux 23

在内部连接的情况下或在左左边一个表连接,在许多情况下,优化会发现,这是更好地在实际执行任何类型的物理的连接前先进行任何过滤(最高选择性) - 所以有显然是更好的物理运作顺序.

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

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

所以:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
WHERE a.something = something
    AND b.something = something
Run Code Online (Sandbox Code Playgroud)

在逻辑上仍相当于:

SELECT *
FROM a
INNER JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
Run Code Online (Sandbox Code Playgroud)

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

另一方面:

SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
WHERE a.something = something
    AND b.something = something
Run Code Online (Sandbox Code Playgroud)

不等同于:

SELECT *
FROM a
LEFT JOIN b
    ON a.id = b.id
    AND a.something = something
    AND b.something = something
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 我无法理解您的`LEFT JOIN`示例.为什么不等同?`WHERE`是否适用于连接的结果? (4认同)
  • @MattArnold 哦,谢谢。简而言之:只要 a 中有行,`left join b ON a.id = b.id` 将始终返回一些内容。基本上`left join b ON a.id = b.id`就像在说“如果你与`b.id`匹配会很好,但如果你不能匹配,只需返回`a`和`b`的空虚拟对象而 `where` 只在 `a.id` 和 `b.id` 匹配时才返回 (3认同)
  • @Toskan 在后者中,如果`a.id = b.id`、`a.something = something` 或`b.something = something` 评估为false,则将为`b` 字段返回带有NULL 值的行;在前者中,如果`a.something = something` 或`b.something = something` 评估为false,则不会返回一行。 (2认同)
  • @Toskan 没错,如果找不到匹配项,`b` 的所有字段都将显示为 NULL。 (2认同)

gbn*_*gbn 21

没关系

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

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

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

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

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


Mar*_*ith 9

只需重新阅读Paul White 在查询优化工具上优秀系列,并记住这个问题.

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

对于(希望!)明显的原因只在开发实例上尝试这个并记住重新启用它们并从缓存中删除任何次优计划.

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)
Run Code Online (Sandbox Code Playgroud)

您可以看到禁用这两个规则后会执行笛卡尔连接和过滤.

规则关闭计划

/*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)
Run Code Online (Sandbox Code Playgroud)

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

计划规则


Gab*_*abe 6

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

  • 无论在实践中实际使用什么顺序,都有一个荣誉的逻辑顺序 (5认同)