为什么 MySQL 8 在使用具有降序主键、2 个索引以及与现有行的有效联接条件的表时不返回任何行

Dar*_*yte 3 mysql index primary-key sorting mysql-8.0

使用 2 个表(A 和 B),可通过它们的 PK 连接,A 的主键按 DESC 排序(PK 按 MySQL 8 允许的降序排列),并且 A 有 2 个按 ASC 排序的索引。

当我执行类似的查询时

SELECT * FROM `A` a
LEFT JOIN `B` b ON a.id <=> b.id
WHERE a.idx1 = 'X' AND a.idx2 = 'Y';
Run Code Online (Sandbox Code Playgroud)

它不会返回任何内容...但是,如果我添加一个精确的条件,例如:

SELECT * FROM `A` a
LEFT JOIN `B` b ON a.id <=> b.id
WHERE a.idx1 = 'X' AND a.idx2 = 'Y' AND a.id = 1337;
Run Code Online (Sandbox Code Playgroud)

它将查找具有指定值作为 PRIMARY KEY 的行。

解释表明,当 MySQL 没有找到任何内容时,它将使用“index_merge_intersection”优化。如果我们禁用“index_merge”优化,第一个查询将按预期返回所有结果。

为什么?

Dar*_*yte 6

它实际上是 MySQL 8.0 的错误(针对 MySQL 8.0.27-debug / 8.0.28 报告),但在 (8.0.23) 之前也存在,并且似乎也存在于 fork (MariaDB/Percona/AWS Aurora/...) 上。

您可以在此处检查错误是否最终得到修复:https://bugs.mysql.com/bug.php ?id=106207

在此之前,您可以使用以下解决方案之一来缓解该问题:

不要在主键上使用 DESC 排序,只能使用 ASC

(这也可以避免由于MySQL无法理解FK可以使用DESC PK而导致INDEX与FOREIGN_KEY重复出现)

或者

从optimizer_switch 设置中禁用index_merge 优化

通过使用以下查询:

SET optimizer_switch='index_merge=off,index_merge_intersection=off';
Run Code Online (Sandbox Code Playgroud)

(或者通过改变optimizer_switch的默认/全局值)所以MySQL将不会陷入这个bug。