MySQL左连接和右连接优化

时间:2017-05-01 18:55:22

标签: mysql join optimization

我一直在这里查找有关此主题的一些文档:https://dev.mysql.com/doc/refman/5.7/en/left-join-optimization.html

但我不明白以下例子:

  

连接优化器计算连接表的顺序。由LEFT JOIN或STRAIGHT_JOIN强制执行的表读取顺序有助于连接优化器更快地完成其工作,因为要检查的表排列更少。这意味着如果执行以下类型的查询,MySQL会对b进行全面扫描,因为LEFT JOIN强制在d之前读取它:

SELECT * FROM a JOIN b LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;

  

在这种情况下,修复与FROM子句中列出a和b的顺序相反:

SELECT * FROM b JOIN a LEFT JOIN c ON (c.key=a.key) LEFT JOIN d ON (d.key=a.key) WHERE b.key=d.key;

为什么订单会进行优化? JOIN和LEFT_JOIN按某种顺序执行吗?

2 个答案:

答案 0 :(得分:1)

我怀疑第一个引用不太正确。我看到LEFT JOIN变成JOIN,然后表格触及'错误'顺序。

无论如何,不​​要担心优化器需要做的工作。在成千上万的慢JOINs中,我只确定了一个案例,其中选择订单的成本很重要。这是一个单个表的多个连接的情况; EAV架构的另一个缺点。无论如何,有一个简单的设置来避免这个问题。

LEFT/RIGHT/plain JOINs 从语义上从左到右完成(无论优化程序选择触摸表的顺序如何)。

如果您担心订购,可以添加括号。例如:

FROM (a JOIN b ON ...) JOIN (c JOIN d ON ...) ON ...

如果您使用的是“commajoin”(FROM a,b...),请不要这样做。但是,它的优先权早就改变了。解决方法是添加parens,以便在更改之后之前的版本中使用相同的SQL。

请勿使用LEFT,除非您需要NULLs来查找“右”行。它只是让读者误以为你期望NULLs

答案 1 :(得分:1)

这个例子在很多方面都是错误的,我不清楚它试图传达什么。为此道歉。我将向文档团队提交一个错误。

一些澄清:

  1. 对于给定的查询,最后一个LEFT JOIN将转换为内部联接。这是因为WHERE子句WHERE b.key = d.key意味着d.key不能为NULL。因此,LENER JOIN生成的任何额外行与INNER JOIN相比将被WHERE子句过滤掉。 (此转换的原则在给定示例后面的段落中进行了描述。)
  2. 第一个LEFT JOIN的ON子句ON(c.key = a.key)使表c依赖于表a,但不依赖于表b。因此,只有连接顺序的要求是在表c之前处理表a。表a和b在查询中列出的顺序不会改变它。
  3. 表b和d可以按任何顺序处理,彼此相互作用,也可以与查询的其他表一起处理。
  4. 本段似乎建议将LEFT JOIN作为减少"表格排列数量的机制来检查"。这没有意义,因为从INNER JOIN更改为LEFT JOIN可能会更改查询的语义。为此,应该使用STRAIGHT_JOIN。
  5. 对于大多数连接查询,执行时间远远超过优化时间。减少"表格排列的数量来检查"可能导致潜在的更有效的排列不被探索。因此,除非需要获得所需的语义,否则不应使用LEFT JOIN。