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
中的 extra
是 NULL
。如果我告诉优化器使用我的覆盖索引,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 关联的列。从磁盘读取页面时,会在缓冲池中创建一份副本。它保留在那里,一个字节一个字节地克隆磁盘上的内容。
查询只读取存储在缓冲池页面中的行。如果请求的行尚未在内存中,则包含该行的页面将立即从磁盘读取到缓冲池中,然后查询继续从内存中读取它。
如果您需要磁盘中的其他页面并且缓冲池已满,则可能会从缓冲池中逐出页面。因此缓冲池可能比磁盘上的整个数据库小得多。随着时间的推移,最常用的页面往往会留在缓冲池中。
Table 结构 table config
:
- 属性(主键)
- 价值
- 描述
查询:
SELECT property, value FROM config
如果我在 (property, value)
上放置一个覆盖索引,优化器仍然选择 PRIMARY
索引,但是 EXPLAIN
中的 extra
是 NULL
。如果我告诉优化器使用我的覆盖索引,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 关联的列。从磁盘读取页面时,会在缓冲池中创建一份副本。它保留在那里,一个字节一个字节地克隆磁盘上的内容。
查询只读取存储在缓冲池页面中的行。如果请求的行尚未在内存中,则包含该行的页面将立即从磁盘读取到缓冲池中,然后查询继续从内存中读取它。
如果您需要磁盘中的其他页面并且缓冲池已满,则可能会从缓冲池中逐出页面。因此缓冲池可能比磁盘上的整个数据库小得多。随着时间的推移,最常用的页面往往会留在缓冲池中。