JOIN条件和WHERE条件之间有执行差异吗?


17

这两个示例查询之间是否存在性能差异?

查询1:

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y'

查询2;

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
   and b.tag = 'Y'

注意唯一的区别是补充条件的位置。第一个使用WHERE子句,第二个将条件添加到ON子句。

当我在Teradata系统上运行这些查询时,说明计划是相同的,并且JOIN步骤显示了每种情况下的附加条件。但是,在有关MySQL的SO问题上,答案之一是建议使用第二种样式,因为WHERE处理是在进行联接之后进行的。

对这样的查询进行编码时,是否要遵循一般规则?我猜它必须是平台相关的,因为它显然对我的数据库没有影响,但这也许只是Teradata的功能。而且,如果它依赖于平台的,我非常希望获得一些文档参考;我真的不知道该找什么。


9
它取决于平台,因为它取决于RDBMS优化器如何处理解析和优化。
Philᵀᴹ

8
链接问题中的答案值得数票。甚至MySQL的原始优化器也将理解这些简单查询是等效的,并且“在所有连接完成后将评估WHERE子句”仅在逻辑级别是正确的,而在实际执行中是正确的。
ypercubeᵀᴹ

1
并不是真正的重复;该问题和答案正在比较“隐式”与“显式” JOIN语法。我要特别询问补充加入条件。
BellevueBob

正如我之前尝试过的那样,不敢在答案中发帖,并获得了很多反对。当有很多联接时,我有一些将条件纳入联接的案例,这会导致更好的查询计划(它会尽早过滤)。结果还是一样。
狗仔队2015年

Answers:


14

根据Sasha Pachev的《理解MySQL内部原理》一书的第9章(解析器和优化器)的第172页

了解MySQL内部

以下是按以下任务对查询的评估的细分:

  • 确定哪些键可用于从表中检索记录,然后为每个表选择最佳键。
  • 对于每个表,确定表扫描是否比键读取更好。如果有很多与键值匹配的记录,则键的优点会降低,并且表扫描会变得更快。
  • 确定查询中存在多个表时,应联接表的顺序。
  • 重写WHERE子句以消除无效代码,减少不必要的计算,并在可能的情况下更改约束,以打开使用键的方式。
  • 从联接中删除未使用的表。
  • 确定是否可以将键用于ORDER BYGROUP BY
  • 尝试简化子查询,并确定可以将其结果缓存到什么程度。
  • 合并视图(将视图引用扩展为宏)

在同一页面上,它显示以下内容:

在MySQL优化程序术语中,每个查询都是一组联接。术语“ 连接”在这里比在SQL命令中使用得更广泛。仅对一个表的查询是简并联接。虽然我们通常不认为从一个表中读取记录是一个联接,但是与常规联接相同的结构和算法可以完美地解决仅一个表的查询问题。

结语

由于存在键,数据量和查询的表达式,MySQL Joins有时可能会为我们自己(或找回我们)做些事情,并得出我们没想到且无法快速解释的结果。

我以前写过关于这个古怪的东西

因为MySQL Query Optimizer可以在查询评估期间关闭某些键。

@Phil的评论帮助我看看如何发布此答案(@Phil的评论+1)

@ypercube的评论(也是该评论的+1)是我的帖子的紧凑版本,因为MySQL的查询优化器是原始的。不幸的是,它必须是因为它处理外部存储引擎。

结论

至于您的实际问题,MySQL查询优化器将确定每个查询完成后的性能指标

  • 计数行
  • 选择键
  • 按摩间歇结果集
  • 哦,是的,进行实际的JOIN

您可能必须通过重写(重构)查询来强制执行顺序

这是您给的第一个查询

select count(*)
from   table1 a
join   table2 b
on     b.key_col=a.key_col
where  b.tag = 'Y';

尝试重写它以首先评估WHERE

select count(*)
from   table1 a
join   (select key_col from table2 where tag='Y') b
on     b.key_col=a.key_col;

那肯定会改变EXPLAIN计划。它可能产生更好或更差的结果。

我曾经在StackOverflow中回答了一个应用此技术的问题。解释是可怕的,但表现是炸药。之所以起作用,是因为存在正确的索引,并且在子查询中使用了LIMIT

与股票价格一样,当涉及到查询并试图表达它们时,也会受到限制,结果可能会有所不同,并且过去的表现并不代表未来的结果。


2
+1可获取有关MySQL特定信息的详细信息,尤其是用于欺骗我以了解“结语”和“结论”之间的区别!
BellevueBob

在我的帖子中,结语是一个小结论。
RolandoMySQLDBA 2013年

6
@Rolando:您可以在最新的MariaDB(5.3和5.5)版本以及最近发布的主要MySQL(5.6)版本中添加有关优化器改进的后果。这可能会使一些重写变得不必要。
ypercubeᵀᴹ

1

对于Oracle,由于mySQL有冗长的说明,因此我们有2种利用优化程序的高级方法。

首先是基于规则的优化(或RBO)。Oracle有15条固定的规则,它解析的每个查询都会按设置的顺序进行尝试。如果无法根据规则1生成优化查询,它将前进到规则2,然后继续前进,直到达到规则15。

有关更多信息:https : //docs.oracle.com/cd/B10500_01/server.920/a96533/rbo.htm

这些影响从11.1及更低版本开始的Oracle RDBMS内核,这些内核尚未转换为基于成本的优化器(aka CBO)。Oracle 11.2及更高版本需要CBO优化器,但是如果用户愿意,可以强制使用旧的RBO方法来优化特定的Sql ID。

相反,Oracle 11.1+的CBO针对相同的SQL ID制定了多个执行计划,并以最低的总体预期成本执行了该计划。它利用了RBO的许多逻辑,但是分析表统计信息来为DB为向最终用户提供数据所需执行的每项操作创建动态执行计划成本。在非常大的表上执行全表扫描确实非常昂贵;在具有10行的表上执行全表扫描很便宜。在RBO中,这些被视为相等的操作。

有关更多信息:https : //oracle-base.com/articles/misc/cost-based-optimizer-and-database-statistics

对于您的特定查询示例:Oracle可能会解析该信息以制定不同的执行计划,因此,从技术上讲,一个要比另一个更好。但是,这可能是最小的差异。对此,Oracle RBO和CBO都希望更多查询1,因为它是在较少条件下在联接上执行的,然后从由联接创建的临时表中过滤出特定的列。


1

如果您有两个查询,并且认为它们是等效的,则可能发生以下情况:

  1. 这两个查询具有相同的执行计划。很好,这就是我们的期望。希望它是查询的最佳执行计划。
  2. 有不同的执行计划。这里有两个子案例。

    2.1查询具有不同的执行计划,但两个计划的执行效果均相同。也可以。对于等效查询,无需生成相同的计划。但是性能应该是相等的。我们再次希望这是最好的。

    2.2查询具有不同的执行计划,一个计划比另一个计划更好。同样,我们有子情况:

    2.2.1计划有所不同,因为查询不相同。因此,请仔细检查它们是否真的等效。在您的情况下,它们实际上是等效的。

    2.2.2计划不同,但查询相同。这意味着优化器还不够成熟。在具有完美优化程序的完美世界中,这不应发生。因此,是的,它取决于平台,您必须研究特定于平台的文档才能了解为什么会发生这种情况。

    2.2.3计划不同,查询等效,数据库软件有错误。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.