【MySql性能调优】1.深入理解Mysql索引底层数据结构与算法

252 阅读7分钟

索引的定义

索引是帮助MySQL高效获取数据的排好序的数据结构

数据库文件位置

image.png

数据库frm和ibd文件的含义

frm文件是MySQL数据库中的表结构定义文件,它记录了表的结构信息,包括表名、列名、数据类型、约束、索引等。在MySQL中,每个表都对应一个.frm文件。

ibd文件是MySQL InnoDB存储引擎中的数据文件,它存储了InnoDB表的数据和索引信息。在InnoDB中,每个表都对应一个.ibd文件,其中包含了表的数据和索引信息。

通常情况下,当你创建一个InnoDB表时,MySQL会同时创建一个.frm文件和一个.ibd文件。其中,.frm文件包含表的结构定义,.ibd文件包含表的数据和索引信息。这两个文件一起组成了完整的InnoDB表。

索引数据结构

  • 二叉树
  • 红黑树
  • Hash表
  • B-Tree

image.png

B-Tree

  • 叶节点具有相同的深度,叶节点的指针为空
  • 所有索引元素不重复
  • 节点中的数据索引从左到右递增排列

image.png

B+Tree(B-Tree变种)

  • 非叶子节点不存储data,只存储索引(冗余),可以放更多的索引
  • 叶子节点包含所有索引字段
  • 叶子节点用指针连接,提高区间访问的性能

image.png

Hash

  • 对索引的key进行一次hash计算就可以定位出数据存储的位置
  • 很多时候Hash索引要比B+ 树索引更高效
  • 仅能满足 “=”,“IN”,不支持范围查询
  • hash冲突问题

image.png

MyISAM索引文件和数据文件是分离的(非聚集)

image.png

InnoDB索引实现(聚集)

表数据文件本身就是按B+Tree组织的一个索引结构文件 聚集索引-叶节点包含了完整的数据记录 为什么建议InnoDB表必须建主键,并且推荐使用整型的自增主键?

在MySQL数据库中,建议InnoDB表必须建主键,这是因为InnoDB存储引擎使用B+树来管理数据,而B+树必须有一个非空的键,作为索引的依据。如果没有主键,InnoDB会自动创建一个隐式主键,这会占用更多的存储空间和CPU资源。

另外,推荐使用整型的自增主键,主要有以下几个原因:

  1. 整型的自增主键可以保证数据的唯一性,确保每条记录都有一个唯一的标识符,方便查询和操作。
  2. 整型的自增主键可以提高查询效率,因为InnoDB使用B+树来管理数据,而B+树是一种平衡树,可以快速查找和排序。使用整型的自增主键可以确保B+树的分裂和合并操作更加高效。
  3. 整型的自增主键可以减少存储空间的占用,因为整型数据类型通常比字符型数据类型更加紧凑,可以占用更少的存储空间。

总之,建议在使用InnoDB存储引擎的MySQL数据库中,每个表都建立一个主键,并且使用整型的自增主键来提高查询效率和减少存储空间占用。

为什么非主键索引结构叶子节点存储的是主键值?(一致性和节省存储空间)

在MySQL数据库中,非主键索引的叶子节点存储的是主键值,这是因为非主键索引是基于B+树数据结构实现的,而B+树是一种多层次的索引结构,每一层都包含一个节点数组和一个指向下一层的指针数组。

在B+树中,叶子节点包含了完整的数据项,而非叶子节点只包含索引项。当我们在非主键上创建索引时,每个索引项都包含了非主键列的值和对应的主键值。这样,当我们查询非主键列时,MySQL就可以通过非主键索引找到对应的主键值,再通过主键索引找到对应的数据行。

因此,为了提高查询效率,非主键索引结构的叶子节点存储的是主键值,而不是完整的数据项。这样可以减少索引的存储空间占用,提高查询效率,并且避免冗余数据的存储。

需要注意的是,如果我们在主键上创建索引,那么主键索引的叶子节点就会包含完整的数据项,而非主键索引的叶子节点就会存储对应的主键值。因此,在创建索引时,需要根据实际情况选择主键索引和非主键索引。

可以将非主键索引的叶子节点存储的主键值类比成目录和文件的关系。目录相当于索引,而文件相当于数据行。在一个目录中,我们可以通过文件名找到对应的文件,而不需要查找整个文件系统。类似地,在非主键索引中,我们可以通过主键值找到对应的数据行,而不需要扫描整个数据表。

举一个有趣的例子,假设你有一个图书馆,每本书都有一个编号和一个名称。如果你想找到书籍的详细信息,你可以通过书籍编号找到对应的书籍,而不需要查找整个图书馆。这个例子中,书籍编号相当于主键值,而书籍名称相当于非主键索引。如果你在图书馆中建立了书籍名称的索引,那么索引结构的叶子节点就会存储对应的书籍编号,而不是书籍的详细信息。这样,当你查找书籍名称时,你可以通过索引找到对应的书籍编号,再通过书籍编号找到对应的书籍详细信息。这样可以大大提高查询效率,并且避免冗余数据的存储。

总之,非主键索引的叶子节点存储的主键值相当于目录和文件的关系,可以通过主键值快速找到对应的数据行。这样可以提高查询效率,并且减少冗余数据的存储。

image.png

image.png

联合索引的底层存储结构长什么样?

image.png

mysql回表的定义

MySQL回表(又称为“二次查询”)是指在使用覆盖索引查询时,如果需要获取的列不在索引列中,MySQL需要再次查询数据表来获取这些列的值。这个过程被称为“回表”。

在MySQL中,如果查询语句只需要访问索引而不需要访问数据行,这就是所谓的索引覆盖查询。索引覆盖查询可以避免访问数据行的开销,提高查询效率。但是,如果需要获取的列不在索引列中,MySQL仍然需要访问数据行来获取数据,这就需要进行回表操作。

需要注意的是,回表操作会带来额外的IO开销,因为MySQL需要从磁盘中读取数据行。因此,如果你需要查询的列不在索引列中,建议直接使用普通查询,而不是使用覆盖索引查询,以避免回表操作带来的额外开销。

总之,MySQL回表是指在使用覆盖索引查询时,如果需要获取的列不在索引列中,MySQL需要再次查询数据表来获取这些列的值。回表操作会带来额外的IO开销,需要根据实际情况进行优化。