原文地址:https://dev.mysql.com/doc/refman/5.7/en/outer-join-optimization.html
译文:
8.2.1.8 外连接优化
外连接包括左连接和右连接。
MySQL按照如下形式实现连接条件A left join B:
1)表B被设置为依赖于表A和A所依赖的所有表;
2)表A被设置为依赖于左连接条件中使用的所有表(除了表B);
3)左连接条件用于决定如何检索表B中的行(换句话说就是,任何where子句中的条件都不会被使用);
4)所有标准的连接优化都会被执行,除非有一个表总是在它所依赖的所有表之后读取。如果存在循环依赖项,则会发生错误;
5)所有标准的where优化都会被执行;
6)如果表A中有一行跟where子句匹配,但是表B中没有与on条件匹配的行,表B中会额外产生一个所有值均为null的行与表A中的对应行匹配;
7)如果你使用左连接区查询在一些表中不存在的行,并且在where条件中有col_name is null,其中col_name是声明为not null类型的列,当MySQL找到匹配left join条件的一行后,它会停止搜索更多的行(针对特定的组合键)。
右连接实现与左连接实现类似,只是表角色颠倒了。关于右连接如何被转化成等价的左连接,可以参考Section 8.2.1.9, “Outer Join Simplification”。
对于一个左连接来说,如果生成的空行对应的where条件总是False,则左连接将变为为内连接。例如,在下面的查询中,如果t2.column1的值为null,则where条件为False。
SELECT * FROM t1 LEFT JOIN t2 ON (column1) WHERE t2.column2=5;
因此,把上面的查询转化成内连接更安全:
SELECT * FROM t1, t2 WHERE t2.column2=5 AND t1.column1=t2.column1;
现在优化器可以在表t1之前使用表t2,如果这样做会产生更好的查询计划的话。要提供有关表连接顺序的提示,可以使用STARTING_JOIN,相关信息可以参考 Section 13.2.9, “SELECT Syntax”。但是,STARTING_JOIN可能会阻止索引的使用,因为它禁用了半连接转换,相关信息可以参考Section 8.2.2.1, “Optimizing Subqueries, Derived Tables, and View References with Semi-Join Transformations”。
PS:由于水平有限,译文中难免存在谬误,欢迎批评指正。