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

标签 mysql innodb clustered-index

config 的表结构:

  • 属性(主键)
  • 值(value)
  • 描述

查询:

SELECT property, value FROM config

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

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

最佳答案

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

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

实际上,当我说“数据页”时,它实际上是聚集索引,即 PRIMARY。 InnoDB 将所有内容存储为索引。在 PRIMARY/聚集索引的情况下,每个条目都包括所有其他列。这有效地使 PRIMARY 索引成为“数据页”。在某些数据库中,他们使用术语“索引组织表”。

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

EXPLAIN 报告中的“使用索引”注释仅在查询从索引中读取所需的所有列时出现,并且该索引是二级索引(不是 PRIMARY)。

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

事实上,当优化器报告“正在使用索引”时,它并不知道相应索引的所有页面、部分页面或没有页面在缓冲池中,还是尚未从磁盘加载。它只知道它可以从一个二级索引中获取它需要的所有列,而无需读取聚簇索引。


回复你的评论:

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

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

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

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

关于mysql - InnoDB:(PK,col1,col2,col3)形式的覆盖索引是否多余?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48218001/

相关文章:

mysql - 使用从其他两个列和第二个表派生的列回显 MySQL 表

mysql - InnoDb Mysql表的行大小限制

clustered-index - H2数据库: clustered indexes support

sql-server-2008 - 将主键添加到具有现有聚集索引的表

mysql - 优化 InnoDB 表和有问题的查询

mysql - phpmyadmin 中的计数语句

mysql - Doctrine - QueryBuilder - 获得结果中最年轻的实体

php - 将 MySQL 数据导出为 CSV,支持泰语

主动/被动拓扑中原始设备上的 Mysql InnoDb

mysql - mysql mariadb 中的 query_cache_min_res_unit 是什么?