表config
的表结构:
查询:
SELECT property, value FROM config
如果我在(property, value)
上添加了覆盖索引,优化程序仍会选择PRIMARY
索引,但extra
中的EXPLAIN
为NULL
。如果我告诉优化器使用我的覆盖索引,extra
中的EXPLAIN
为USING INDEX
。
这里到底发生了什么?为什么优化器默认选择覆盖索引上的PRIMARY
索引?我是否通过告诉优化器使用覆盖索引来避免磁盘IO?
答案 0 :(得分:2)
InnoDB索引不会自动存储在缓冲池中。它们存储在磁盘上。索引页和数据页都存储在磁盘上。
索引页面和数据页可以复制到内存中的缓冲池中,具体取决于先前的查询是否已请求它们。但这不能保证。
实际上当我说“数据页面”时,它确实是聚集索引,即PRIMARY。 InnoDB将所有内容存储为索引。在PRIMARY /聚集索引的情况下,每个条目包括所有其他列。这有效地使PRIMARY索引成为“数据页”。在某些数据库中,他们使用术语“索引组织表”。
当优化器选择您的PRIMARY索引时,不用说主键读取将能够获得所有其他列而无需进一步查找(除了扩展到额外页面的blob / text数据)。
EXPLAIN报告中的“使用索引”注释仅在查询从索引中读取所需的所有列时显示,和索引是辅助索引(不是PRIMARY)。
“使用索引”与内存与磁盘读取无关。当请求页面时,如果它在缓冲池中,它将从内存中读取。如果它不在缓冲池中,它将从磁盘复制到缓冲池中,无论它是PRIMARY还是辅助索引。
实际上,当优化程序报告“使用索引”时,它不知道相应索引的全部,部分或全部页面是否都在缓冲池中,或者尚未从磁盘加载。它只知道它可以从一个二级索引中获取所需的所有列,而无需读取聚簇索引。
重新评论:
是的,整行都在内存中,而不仅仅是PK。
缓冲池包含 pages ,与磁盘上的内容完全相同。页面包含两行或更多行数据,这意味着PK加上与该PK相关联的列。从磁盘读取页面时,会在缓冲池中创建它的副本。在那里,它逐字节地保留了磁盘上的内容。
查询仅读取缓冲池中页面中存储的行。如果请求的行还没有在内存中,那么保存该行的页面将立即从磁盘读入缓冲池,然后查询继续从内存中读取它。
如果您需要磁盘中的其他页面且缓冲池已满,则可能会从缓冲池中逐出页面。因此,缓冲池可能比磁盘上的总数据库小得多。随着时间的推移,最常用的页面往往会留在缓冲池中。