【问题标题】:InnoDB: Is a covering index in the form of (PK, col1, col2, col3) redundant?InnoDB:(PK,col1,col2,col3)形式的覆盖索引是否多余?
【发布时间】:2018-06-21 10:16:53
【问题描述】:

config的表结构:

  • 属性(主键)
  • 价值
  • 说明

查询:

SELECT property, value FROM config

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

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

【问题讨论】:

  • 如果选择表的所有记录,则不需要索引。例如,当使用where 子句时,索引就派上用场了。经验法则是为where 子句中使用的所有列定义索引。
  • 我使用覆盖索引的目标是从内存而不是磁盘中检索数据。我感到困惑的是,当我让优化器使用它对 PK 的选择而不是我的覆盖索引时,是否发生了磁盘 IO。
  • 通常优化器会选择比你更好的方式。并且索引并不意味着数据存储在内存中。索引有助于查找数据。你应该阅读它。我认为您并不真正了解它们的工作原理
  • 来自dev.mysql.com/doc/refman/5.5/en/optimizing-innodb-queries.html:“如果索引包含结果集所需的所有列(称为覆盖索引),则查询可能完全避免读取表数据。”由于 InnoDB 索引存储在内存中(给定足够大的内存池),这意味着数据正在有效地从内存中检索。
  • 是的——它可能会。但这不是索引的实际目的。

标签: mysql innodb clustered-index


【解决方案1】:

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

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

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

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

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

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

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


你的评论:

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

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

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

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

【讨论】:

  • 谢谢,这是一个非常有用的解释。那么,如果 PK 实际上包括所有列,这是否意味着整行(不包括 BLOB/TEXT 列)都被缓冲到内存中?我一直认为内存中的内容是 PK 列和指向磁盘上整行的指针。
  • 内存中没有任何内容,除非某些先前的查询导致它被加载到内存中。这篇博客文章很好地向您展示了您可以运行查询以确定发生了什么的细节。 michael.bouvy.net/blog/en/2015/01/18/… InnoTop 也是一个很好的工具,可以让你远离细节。根据数据的性质,innodb 缓冲池无疑是优化 mysql 性能的宝贵资产,但根据我的经验,它不能替代 memcached 或 redis 等缓存服务器。
猜你喜欢
  • 2018-10-13
  • 2016-08-12
  • 2022-06-15
  • 1970-01-01
  • 2016-03-30
  • 1970-01-01
  • 1970-01-01
  • 2021-01-31
  • 1970-01-01
相关资源
最近更新 更多