Mysql - LEFT JOIN 比 INNER JOIN 快得多

ben*_*n.d 4 mysql performance inner-join left-join mariadb

我有两张桌子

表 X:数百万条记录

|-----|-----|-----|-----|
|  a  |  b  |  c  |  d  |
|-----|-----|-----|-----|
Run Code Online (Sandbox Code Playgroud)

表Y:只有几条记录

|-----|-----|
|  e  |  f  |
|-----|-----|
Run Code Online (Sandbox Code Playgroud)

X.d允许我加入两个表X.d = Y.e

我有以下索引:

  • (Xa)
  • (Xb)
  • (Xc)
  • (Xd)
  • (Xa、Xb、Xc、Xd)
  • (叶)

我们的一个应用程序正在执行以下查询,该查询需要很长时间才能运行:

SELECT * 
FROM X
INNER JOIN Y ON X.d = Y.e
WHERE 
      X.a in (1, 2, 3)
  AND X.b IS NULL
  AND X.c in (4, 5 ,6)
  AND X.d in (7, 8, 9)
Run Code Online (Sandbox Code Playgroud)

将 更改INNER JOIN为 a后LEFT JOIN,查询速度非常快:

SELECT * 
FROM X
LEFT JOIN Y ON X.d = Y.e
WHERE 
      X.a in (1, 2, 3)
      AND X.b IS NULL
      AND X.c in (4, 5 ,6)
      AND X.d in (7, 8, 9)
Run Code Online (Sandbox Code Playgroud)

查看这些查询的解释计划,第一个查询正在执行 a full scan,而第二个查询仅在我的复合索引上执行 a Index Scan (range)。我在 SO 上看到了其他帖子,但他们有不同的场景。

为什么计划有如此大的差异?

Tim*_*key 6

不同计划的原因是 LEFT JOIN 将强制表的连接顺序与它们在查询中出现的顺序相匹配。如果没有左连接,优化器将为您选择连接顺序,在这种情况下,它将首先选择非常小的表。(您可以在您的explain通过查看表列出的顺序来看到这一点。)一旦切换连接顺序,X 的索引就会更改为 KEY d,它必须具有比复合键大得多的数据集。

要解决此问题,请将您的选择更改为SELECT STRAIGHT_JOIN *. 这比USE INDEX以便优化器仍然可以为表 X 选择最佳键...您可能会找到比 a、b、c、d 更好的复合键,或者如果 X 中的数据发生巨大变化,则您的其他键之一过了一点可能会更好。

我必须指出,通常不能直接切换到 LEFT JOIN。返回的数据通常会不同!