由于选择性低(所有 NULL),MariaDB 不在 1 列自连接上使用索引
MariaDB doesn't use index on 1 column self-join due to low selectivity (all NULLs)
我们有一个查询在我们的 table 之一中查找重复项,基于一个很少可用的标识符,我们称之为 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)
扫描整个 table.
的方法
但是NULL
s不能彼此相等!那么为什么它要尝试比较每一对行呢?
我知道如果索引的选择性太低,MySQL/MariaDB 将不会使用索引。我相信这里就是这种情况。事实上,索引中只有 1 个值似乎意味着查询几乎是瞬时的。
table 是一个 InnoDB table。
InnoDB 可能不够聪明,无法意识到与 NULL
的比较总是 NULL
,因此是错误的。也许它只是决定"all values are the same, so they must be equal"(但其实我真的不知道)。
作为解决方法,添加 ... AND a.rareIdentifier IS NOT NULL
应该会给优化器足够的提示。
在大多数情况下这可能会更快,特别是如果有许多行具有相同的 rareIdentifier
。
SELECT rareIdentifier, MIN(id), MAX(id), COUNT(*)
FROM tbl
WHERE rareIdentifier IS NOT NULL
GROUP BY rareIdentifier
HAVING COUNT(*) > 1;
或者您可以使用 GROUP_CONCAT(id)
代替最小值和最大值。 (但是,如果有很多重复项,列表将被截断。)
假设 InnoDB 和 INDEX(rareIdentifier)
,这个 SELECT
应该是一个非常有效的 'range' 索引扫描。
回到你的问题...
actually had 0 rows ... MariaDB decided not to use the index
我以前在 MySQL 的旧版本中看到很多。我想知道 Oracle 是否已修复,但 MariaDB 未修复。
我们有一个查询在我们的 table 之一中查找重复项,基于一个很少可用的标识符,我们称之为 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)
扫描整个 table.
但是NULL
s不能彼此相等!那么为什么它要尝试比较每一对行呢?
我知道如果索引的选择性太低,MySQL/MariaDB 将不会使用索引。我相信这里就是这种情况。事实上,索引中只有 1 个值似乎意味着查询几乎是瞬时的。
table 是一个 InnoDB table。
InnoDB 可能不够聪明,无法意识到与 NULL
的比较总是 NULL
,因此是错误的。也许它只是决定"all values are the same, so they must be equal"(但其实我真的不知道)。
作为解决方法,添加 ... AND a.rareIdentifier IS NOT NULL
应该会给优化器足够的提示。
在大多数情况下这可能会更快,特别是如果有许多行具有相同的 rareIdentifier
。
SELECT rareIdentifier, MIN(id), MAX(id), COUNT(*)
FROM tbl
WHERE rareIdentifier IS NOT NULL
GROUP BY rareIdentifier
HAVING COUNT(*) > 1;
或者您可以使用 GROUP_CONCAT(id)
代替最小值和最大值。 (但是,如果有很多重复项,列表将被截断。)
假设 InnoDB 和 INDEX(rareIdentifier)
,这个 SELECT
应该是一个非常有效的 'range' 索引扫描。
回到你的问题...
actually had 0 rows ... MariaDB decided not to use the index
我以前在 MySQL 的旧版本中看到很多。我想知道 Oracle 是否已修复,但 MariaDB 未修复。