我在向表添加新索引时遇到一些问题,我想知道为什么 MySQL 不使用新索引。
我注意到,只有当我的 SELECT 语句请求不属于索引的其他列时才会发生这种情况(例如
SELECT *
不起作用,而 SELECT id, otherId
起作用)。
有人可以向我解释一下为什么MySQL选择进行表扫描而不是使用索引吗?
该表由多列组成,即
id
和 otherId
。 id
是我的主键,而 otherId
也应该被索引。 otherId
可以为空并且是唯一的。
model Entity {
id String @id @default(cuid())
otherId String? @unique
// Few more ...
}
SELECT
COUNT(DISTINCT Entity.otherId) as cardinality,
COUNT(*) as totalRows,
COUNT(Entity.otherId) as nonNullRows,
COUNT(DISTINCT Entity.otherId) / COUNT(*) as selectivity
FROM
Entity
基数 | 总行数 | 非空行 | 选择性 |
---|---|---|---|
171 | 1187 | 171 | 0.1441 |
这个不使用索引,但我希望它会。
EXPLAIN SELECT * FROM Entity WHERE Entity.otherId = ?;
id | 选择类型 | 桌子 | 分区 | 类型 | 可能的键 | 键 | key_len | 参考 | 行 | 过滤 | 额外 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 简单 | 实体 | 全部 | Entity_otherId_key | 1187 | 10 | 使用地点 |
这个确实使用了索引。
EXPLAIN SELECT id, otherId FROM Entity WHERE Entity.otherId = ?;
id | 选择类型 | 桌子 | 分区 | 类型 | 可能的键 | 键 | key_len | 参考 | 行 | 过滤 | 额外 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 简单 | 实体 | 索引 | Entity_otherId_key | Entity_otherId_key | 767 | 1187 | 10 | 使用地点;使用索引 |
SHOW INDEXES from Entity;
桌子 | 非唯一 | 密钥名称 | 索引中的序列 | 列_名称 | 整理 | 基数 | 子_部分 | 包装好 | 空 | 索引_类型 | 评论 | 索引_评论 | 可见 | 表情 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
实体 | 0 | 小学 | 1 | id | A | 1187 | BTREE | 是 | ||||||
实体 | 0 | Entity_otherId_key | 1 | 其他ID | A | 172 | 是 | BTREE | 是 |
8.2.0
您的查询均不执行任何行限制(WHERE 子句)或排序(ORDER BY 子句)。所以他们必须检查每一行。
这得到了两个 EXPLAIN 结果的
rows
列的支持。两者都显示 1187。
但是
type: ALL
和type: index
有什么区别?
第一个是表扫描。该查询将检查表中的每一行。由于 MVCC,它必须这样做才能对它们进行计数。因此查询的成本与行数成正比。
第二个是索引扫描。这比表扫描稍好一些,但它仍然需要检查命名索引中的每个条目来对它们进行计数。成本也与行数成正比,但它可能能够检查更少的页面来单独读取索引而不是整个表。
解释“使用索引”中的注释让您相信它已经优化了。严格来说,它确实为此查询使用了索引,但它使用索引的方式与搜索或排序不同。