MySQL 正在使用 possible_keys 中未列出的索引

bmu*_*uer 4 mysql index

在一个非常基本的设置中,我有一个包含一些字段的表:

firstname (VARCHAR)
lastname (VARCHAR)
country (INT)
email (VARCHAR)
Run Code Online (Sandbox Code Playgroud)

我在 Index 中创建了 2 个字段:

CREATE INDEX countr_email_idx ON person (country, email)
Run Code Online (Sandbox Code Playgroud)

这是学校的一个简单例子,因此不应假设该索引是否有任何用处。

现在,当我通过电子邮件字段查询简单的 Select 时,MySQL 文档指出,因为它不是索引的最左侧属性,所以无法使用它。possible_keys当我使用以下命令运行查询时,这也反映在空值中EXPLAIN

EXPLAIN SELECT passenger_id, email
FROM passengerdetails
WHERE email LIKE 'bob%'
Run Code Online (Sandbox Code Playgroud)

这产生

id | select_type | table            | type  | possible_keys | key              | key_len | ref  | rows  | Extra
1  | SIMPLE      | passengerdetails | index | NULL          | countr_email_idx | 225     | NULL | 36370 | Using where; Using index
Run Code Online (Sandbox Code Playgroud)

然而,countr_email_idx毕竟被列为使用的索引。为什么会出现这种情况?

Joh*_* N. 5

MySQL 的文档包含以下有关EXPLAIN 输出格式的信息:

key 可能会命名 possible_keys 值中不存在的索引。如果没有一个 possible_keys 索引适合查找行,但查询选择的所有列都是其他索引的列,则可能会发生这种情况。也就是说,命名索引覆盖了选定的列,因此虽然它不用于确定要检索哪些行,但索引扫描比数据行扫描更有效。

因此,虽然不需要索引查找,但 MySQL 仍将通过索引检索数据,而不是通过正常的数据行扫描。


关于主键索引的附录

假设您使用的是 InnoDB 引擎,并且表上的 PKpassengerdetails是基于 的passenger_id,那么所有其他二级索引都将基于该主键,如官方文档中的14.11.9 聚集索引和二级索引一文所述。

即使您没有自己创建主聚集索引,MySQL 也会为您创建以确保快速查询。这被记录为:

如果没有为表定义主键,MySQL 会找到第一个唯一索引,其中所有键列都不为空,并且 InnoDB 将其用作聚集索引。

和:

如果表没有 PRIMARY KEY 或合适的 UNIQUE 索引,InnoDB 会在包含行 ID 值的合成列上内部生成隐藏的聚集索引。这些行按照 InnoDB 分配给此类表中的行的 ID 进行排序。行 ID 是一个 6 字节字段,随着新行的插入而单调增加。因此,按行 ID 排序的行实际上是按插入顺序排列的。