MySql索引数据结构

什么是索引

索引是数据库管理系统中用以高速获取数据的一个排好序数据结构。你可以把它当作书本的目录,通过书本目录的页码,我们能快速的定位到想要查询到的位置。如果没有目录,我们只能一页页的去寻找内容。

索引的选择

下面看一个例子:
image
图中例子左侧为数据库表,右侧为索引,通过这个红黑树索引,便可以快速找到数据对应的物理地址(注意数据即使相邻,他们的物理地址也不一定相邻,这是由于磁盘的随机读写性)。
但是实际中很少使用二叉树来充当索引的数据结构,下面逐一分析:

  • 二叉树:
    image
    如图所示的二叉树,倘若存储的数据为顺序存储,二叉树无法实现快速搜索。其数据结构更像链表。
  • 红黑树(二叉平衡树):
    image
    红黑树虽然解决了顺序插入的问题,但是红黑树的查找次数与树高正相关,倘若查找的节点为叶子节点,那么需要查找的次数等于树高。(想看红黑树插入过程的可以访问如下链接去查看数据结构可视化
    由于索引一般以文件形式存放在磁盘中,而磁盘I/O的速度远远低于内存I/O。因此降低磁盘I/O的次数可以极大的提高读取时间。
    目前大部分数据库系统及文件系统都采用B-Tree或其变种B+Tree作为索引结构。

B树与B+树

B树

一个m阶B树的属性有:

每一个节点最多有 m 个子节点
每一个非叶子节点(除根节点)最少有 ⌈m/2⌉ 个子节点
如果根节点不是叶子节点,那么它至少有两个子节点
有 k 个子节点的非叶子节点拥有 k − 1 个关键字
所有的叶子节点都在同一层

下图为3阶B树:
image

B+树

一个m阶B+树的属性有:

每一个节点最多有m个字节点
每一个非叶子节点(除根节点)最少有 ⌈m/2⌉ 个子节点
如果根节点不是叶子节点,那么它至少有两个子节点
有 k 个子节点的非叶子节点拥有 k 个关键字
且B+树叶子节点的关键字从小到大有序排列,左边结尾数据都会保存右边节点开始数据的指针

下图为3阶B+树:
image

Mysql中的B树与B+树

B树

叶子节点具有相同深度
所有索引元素不重复
节点中的数据索引从左往右递增排序

image

B+树

非叶子节点不存储data,只存索引(冗余)
叶子节点包含所有索引字段
叶子节点区间有指向相邻节点的指针

image

索引的类型

按照数据结构分类可分为:B+树索引、Hash索引、全文(Full-text)索引。
按照物理存储分类可分为:聚集索引、辅助索引。
按照字段特性分类可分为:主键索引、普通索引、前缀索引。
按照字段个数分类可分为:单列索引、组合索引。
本文只介绍部分索引类型的大概概念,详细的可以参考如下博客
MySQL索引有哪些分类,你真的清楚吗?

聚集索引

聚集索引又称聚簇索引,它的每个叶子节点都存储了完整的表数据,叶子节点件按照id递增连接,可以方便的跨”页“查找数据。
image

辅助索引(二级索引)

辅助索引存储的是聚集索引所在列的值。

image

回表查询

由于辅助索引存储的表数据不完整,因为当索引通过辅助索引去查询到聚集索引的值后,需要去到聚集索引中查询,以获得更多的表数据。
但是回表不是一定会发生的,如果Select查询的字段在单个辅助索引中都能查询到,就不需要回表。此时的辅助索引被称为覆盖索引,或称它触发了索引覆盖
可以用Explain命令查看SQL语句的执行计划,执行计划的Extra字段中若出现Using index,表示查询触发了索引覆盖。

两种索引引擎的实现

MyISAM实现索引

本地文件夹(Mysql文件目录\data\数据库名)中可以查看到相应数据库表存放在磁盘中的文件。
image

MyISAM中索引文件与数据文件分开存放,因此MyISAM中data字段存储的是表数据的物理地址。而MyISAM的主键索引和辅助索引结构没什么不同,区别只是主键索引要求key值是唯一的,但是辅助索引key值可以重复。所以MyISAM表可以没有主键
由于MyISAM的索引文件和数据文件分开,所以MyISAM的索引都是非聚集索引

image

InnoDB实现索引

主键索引:
InnoDB的主键索引包含了所有的表数据,因此又被成为聚集索引。InnoDB要求数据表必须要有聚集索引,它默认会在主键字段上建立聚集索引。
如果没有主键的话,它会将表中第一个非空的且数据唯一的列建立成聚集索引。如果不存在这种列,Mysql会字段生成一个隐式的自增的id列,并在这一列上建立聚集索引。这个字段长度为6个字节,类型为长整型。

image

辅助索引(二级索引):
InnoDB的辅助索引使用主键作为data域。因此InnoDB不应该使用过长的字段来做主键,否则主键索引过大,辅助索引也相应的变大。
检索辅助索引的时候,需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

image

面试题

Mysql为什么选用B+树?

Mysql以”页“为单位做一个区间,通过上面的分析可以知道影响树的查找速度的因素是查找的次数,即树高。那么如果一”页“中能够存放的索引节点越多,那么树的树高越低。Mysql中的一个页的大小为16K。
通过命令show global status like "Innodb_page_size"看到该值是16384。
一页的大小是有限的,相较于B树结构,B+树data数据只存放在叶子节点中,那么在非叶子节点可以存放的索引节点就更多,这样就可以大大减少查询次数,提高效率。

为什么InnoDB必须要建立主键?

InnoDB要求数据表必须要有聚集索引,它默认会在主键字段上建立聚集索引。如果没有主键的话,它会将表中第一个非空的且数据唯一的列建立成聚集索引。如果不存在这种列,Mysql会字段生成一个隐式的自增的id列,并在这一列上建立聚集索引。这个字段长度为6个字节,类型为长整型。
让Mysql来建立字段并且维护会十分消耗Mysql的性能,因此最好自己建主键。

为什么InnoDB的主键不应该使用过长的字段?

InnoDB的辅助索引使用主键作为data域。如果主键使用过长的字段,会导致所有的辅助索引文件过大。

为什么InnoDB的主键要求单调自增?

因为InnoDB索引文件本身是一颗B+树,非单调的主键会导致在插入新记录时,数据文件为了维持B+树的递增特性而频繁的分裂调整,十分低效。而使用自增字段作为主键则可以避免B+树的频繁分裂。

posted @ 2021-04-13 18:04  君子酱  阅读(620)  评论(0编辑  收藏  举报