InnoDB:(PK,col1,col2,col3)形式的覆盖索引是否多余?

InnoDB: Is a covering index in the form of (PK, col1, col2, col3) redundant?

Table 结构 table config:

查询:

SELECT property, value FROM config

如果我在 (property, value) 上放置一个覆盖索引,优化器仍然选择 PRIMARY 索引,但是 EXPLAIN 中的 extraNULL。如果我告诉优化器使用我的覆盖索引,EXPLAIN 中的 extra 就是 USING INDEX.

这里究竟发生了什么?为什么优化器默认选择 PRIMARY 索引而不是我的覆盖索引?我是否通过告诉优化器使用我的覆盖索引来避免磁盘 IO?

InnoDB 索引不会自动存储在缓冲池中。它们存储在磁盘上。索引页和数据页都存储在磁盘上。

索引页和数据页都可以复制到内存中的缓冲池中,这取决于之前的查询是否请求过它们。但这并不能保证。

实际上,当我说 "data pages" 时,这实际上是聚簇索引,即 PRIMARY。 InnoDB 将所有内容存储为索引。在 PRIMARY/clustered 索引的情况下,每个条目都包含所有其他列。这有效地使 PRIMARY 索引成为 "data pages." 在某些数据库中,他们使用术语 "index-organized table."

当优化器选择您的 PRIMARY 索引时,不用说主键读取将能够获取所有其他列而无需任何进一步查找(除了扩展到额外页面的 blob/text 数据) .

EXPLAIN报告中的"Using index"注释只有当查询从索引中读取了它需要的所有列时才会出现,并且该索引是二级索引(不是小学)。

"Using index" 与内存中与从磁盘读取无关。当一个页面被请求时,如果它在缓冲池中,它将从内存中读取。如果它不在缓冲池中,它将被从磁盘复制到缓冲池中,无论它是 PRIMARY 索引还是二级索引。

事实上,当优化器报告 "Using index" 时,它不知道相应索引的所有、部分或 none 页面是否在缓冲池中,或者尚未从磁盘加载。它只知道它可以从一个二级索引中获取它需要的所有列,而不需要读取聚集索引。


回复您的评论:

是的,整行都在内存中,而不仅仅是 PK。

缓冲池包含 ,与磁盘上的完全一样。这些页面包含两行或多行数据,这意味着 PK 加上与该 PK 关联的列。从磁盘读取页面时,会在缓冲池中创建一份副本。它保留在那里,一个字节一个字节地克隆磁盘上的内容。

查询只读取存储在缓冲池页面中的行。如果请求的行尚未在内存中,则包含该行的页面将立即从磁盘读取到缓冲池中,然后查询继续从内存中读取它。

如果您需要磁盘中的其他页面并且缓冲池已满,则可能会从缓冲池中逐出页面。因此缓冲池可能比磁盘上的整个数据库小得多。随着时间的推移,最常用的页面往往会留在缓冲池中。