MySql之索引结构

156 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第5天,点击查看活动详情

什么是索引

所谓索引,就像一本书的目录,当我们看某一章某一节时,不需要从第一页开始翻,而是根据目录定位直接翻到目标页数。数据库的索引也是这样,查询某一行数据,不是全盘扫描,而是根据索引快速定位数据所在数据。因此,索引的定义就是帮助存储引擎快速获取数据的一种数据结构,形象的说就是索引是数据的目录
下图是 MySQL 的结构图,索引和数据就是位于存储引擎中: 1623727651911_20170928110355446.png

索引分类

索引分类.png

按数据结构分类

从数据结构的角度来看,MySQL 常见索引有 B+Tree 索引、hash 索引、full-text 索引。 InnoDB 是在 MySQL 5.5 之后成为默认的 MySQL 存储引擎,B+Tree 索引类型也是 MySQL 存储引擎采用最多的索引类型。

在创建表时,InnoDB 存储引擎会根据不同的场景选择不同的列作为索引:

  • 如果有主键,默认会使用主键作为聚簇索引的索引键(key);
  • 如果没有主键,就选择第一个不包含 NULL 值的唯一列作为聚簇索引的索引键(key);
  • 在上面两个都没有的情况下,InnoDB 将自动生成一个隐式自增 id 列作为聚簇索引的索引键(key);

按物理存储分类

从物理存储的角度来看,索引分为聚簇索引(主键索引)、二级索引(辅助索引)。

两者主要区别在于:

  • 聚簇索引中叶子节点存储的是主键和数据
  • 二级索引中叶子节点存储的是二级索引和主键值

聚簇索引.png

二级索引.png 所以,在查询时使用了二级索引,如果查询的数据能在二级索引里查询的到,那么就不需要回表,这个过程就是覆盖索引

如果查询的数据不在二级索引里,就会先检索二级索引,找到对应的叶子节点,获取到主键值后,然后再检索主键索引,就能查询到数据了,这个过程就是回表,也就是说需要查询两次B+tree,如下图所示。

二级索引查找数据.png

按字段特性分类

从字段特性的角度来看,索引分为主键索引、唯一索引、普通索引、前缀索引。

  • 主键索引就是建立在主键字段上的索引,通常在创建表的时候一起创建,一张表最多只有一个主键索引,索引列的值不允许有空值。
PRIMARY KEY (index_column_1) USING BTREE
  • 唯一索引建立在 UNIQUE 字段上的索引,一张表可以有多个唯一索引,索引列的值必须唯一,但是允许有空值。
UNIQUE KEY(index_column_1,index_column_2,...) 
  • 普通索引就是建立在普通字段上的索引,既不要求字段为主键,也不要求字段为 UNIQUE。
INDEX(index_column_1,index_column_2,...)
  • 前缀索引是指对字符类型字段的前几个字符建立的索引,而不是在整个字段上建立的索引,前缀索引可以建立在字段类型为 char、 varchar、binary、varbinary 的列上,通过使用前缀索引可以减少索引占用的存储空间,提升查询效率。
INDEX(column_name(length))

按字段个数分类

从字段个数的角度来看,索引分为单列索引(主键索引)、联合索引(复合索引)。

创建联合索引

CREATE INDEX index_student_no_name ON product(student_no, name);

所谓联合索引,就是将多个字段组合成一个索引,该索引就被称为联合索引。如下图所示:

联合索引.png 可以看到,联合索引的非叶子节点用两个字段的值作为 B+Tree 的 key 值。当在联合索引查询数据时,先按 student_no 字段比较,在 student_no 相同的情况下再按 name 字段比较。 也就是说,联合索引查询的 B+Tree 是先按 student_no 进行排序,然后再student_no 相同的情况再按 name 字段排序。

MySQL为什么使用B+树

数据库的索引是保存到磁盘上的,因此当我们通过索引查找某行数据的时候,就需要先从磁盘读取索引到内存,再通过索引从磁盘中找到某行数据,然后读入到内存,也就是说查询过程中会发生多次磁盘 I/O,而磁盘 I/O 次数越多,所消耗的时间也就越大。

所以总结有两点原因:

  • B+Tree 只在叶子节点存储数据,B+Tree 的非叶子节点需要存储的数据就很少,在相同的磁盘 I/O 次数下,能够读取更多的节点,就能查询更多的数据。
  • B+Tree 叶子节点采用的是双链表连接,适合 MySQL 中常见的基于范围的顺序查找

B+Tree 存储千万级的数据只需要 3-4 层高度就可以满足,这意味着从千万级的表查询目标数据最多需要 3-4 次磁盘 I/O,所以B+Tree 相比于 B 树和二叉树来说,最大的优势在于查询效率很高,因为即使在数据量很大的情况,查询一个数据的磁盘 I/O 依然维持在 3-4次。