我们有一个查询在我们的一个表中查找重复项,基于很少可用的标识符,我们称之为rareIdentifier INT(10) UNSIGNED NULL
。我们在此列上有一个单列常规旧索引。
有问题的查询如下所示:
SELECT a.id, b.id FROM
widget a INNER JOIN widget b
ON a.rareIdentifier = b.rareIdentifier;
问题是,对于最近的重复查找运行,我们实际上有0
行,其值为rareIdentifier
;即此列的所有行都有NULL
。 MariaDB决定不使用索引,选择扫描整个表格的Using join buffer (flat, BNL join)
方法。
但是NULL
s不能相等!那么为什么要尝试比较每对行呢?
据我所知,如果MySQL / MariaDB的选择性太低,它将不会使用索引。我相信这就是这种情况。事实上,似乎只在索引中有一个值意味着查询几乎是即时的。
该表是InnoDB表。
答案 0 :(得分:0)
InnoDB可能不够智能,因为与NULL
相比总是NULL
,因此是假的。也许它只是决定"所有值都是相同的,所以它们必须相等" (但实际上我真的不知道)。
作为一种解决方法,添加... AND a.rareIdentifier IS NOT NULL
应该为优化程序提供足够的提示。
答案 1 :(得分:0)
在大多数情况下,这可能会更快,特别是如果有许多行具有相同的rareIdentifier
。
SELECT rareIdentifier, MIN(id), MAX(id), COUNT(*)
FROM tbl
WHERE rareIdentifier IS NOT NULL
GROUP BY rareIdentifier
HAVING COUNT(*) > 1;
或者您可以使用GROUP_CONCAT(id)
代替min&最大。 (但是,如果有很多重复,则列表将被截断。)
假设InnoDB和INDEX(rareIdentifier)
,这个SELECT
应该是一个非常有效的范围'扫描索引。
回到你的问题......
实际上有0行...... MariaDB决定不使用索引
我曾经在旧版本的MySQL中看到很多东西。我想知道Oracle是否已修复,但MariaDB错过了修复程序。