目录

  • 前言
  • 索引
  • 问题
  • 创建索引原则


前言

MySQL提升查询效率的一种特别高效的方式就是建立索引,那么MySQL是怎么提升我们的查询效率的呢,本文从索引的数据结构方面开始分析

索引

mysql有多种类型的索引,主要有以下几种

  • 主键索引:基于主键创建的索引
  • 普通索引:普通字段上面建立的索引
  • 唯一索引:唯一字段上面可以建立的索引
  • 全文索引:大字段上可以建立的索引
  • 前缀索引:基于字段的前n个字建立的索引
  • 联合索引:基于多个字段建立的索引

我们在某个字段上建立一个索引后,服务端会做什么操作呢?

本文介绍MySQL5.7版本之后默认的存储引擎innoDB中的索引结构

首先我们得知道索引的数据结构,innoDB中的索引的数据结构是以B+树的数据结构创建的,何为B+树呢?B+树有什么特点呢?我们可以看下图

mysql 默认前缀索引长度 mysql前缀索引原理_数据结构


1、除了主键索引外的索引的数据结构如上图,是B树的升级版,每一个节点称为一个page

2、B+树是一个有序的数据结构,每个数据上存放索引字段的值以及一个指针

3、只有叶子节点存放了数据,叶子节点存放了主键的id

4、每一个page可以存放16kb的大小,也就是一个page可以存放很多数据,所以根据统计,在千万级别的数据量下,数的深度一般只需要2(避免io太多影响性能)

主键索引

主键索引的结构和上述类似,唯一的不同点在于主键索引的叶子节点存储的是完整的一条数据。

主键索引默认使用主键来创建,如果没有设置主键则优先查找是否存在非空的唯一索引,如果还是没有则使用默认的rowid作为主键索引

根据一个索引字段查询后的流程:

  1. 如果查询的字段存在索引,那么根据上述结构,先查找到主键的id,比如查找值为28的数据,那么在第一层节点找到P2 > 到第二层中查找到在P1 > 到第三层找到在第四个页的第一个数据(假设此时查找到对应的主键id为30),上述每一个页中查找可以使用二分查找法,二分查找的效率相对是比较高的
  2. 查找到主键id为30,在主键索引中再次根据上述规则查找,最终找到叶子节点上的数据(此过程称之为’回表’)

也就是说依赖索引查询数据时一般情况会进行两次B+树的扫描,扫描的过程大量使用了二分查找法,相对于全表扫描可以大大提升性能(一般情况下创建索引后效率至少可以提升50倍以上

问题

基于上述结构很多同学会存在一些疑问

1、为什么使用B+树的数据结构,而不是采用别的数据结构,B+树的结构有什么优势
B树:相交于B树的区别是B+树只有叶子节点存放数据,这样可以保证不同的查询的时间是相对稳定的,范围查找时可以直接在叶子节点进行范围查找
hash:hash在查询数据方面的效率可以达到O(1),那么为什么不使用hash呢,原因是hash的数据是无序的,如果需要根据范围查找就无法使用到索引了,并且造成hash冲突后会导致io次数较多而影响性能

2、为什么普通索引的叶子节点不直接存放数据的内存地址,这样可以避免再次进行回表查询?
因为数据进行增删时可能会导致其他数据的内存地址发生改变,而主键是不会受影响的

3、为什么不建议在无序字段上使用索引
因为有序字段插入数据时可以直接追加在叶子节点的最后,而无序节点则可能插入在中间的某个page上,插入后如果page存放不下了还会导致其他数据被分配到其他page,造成page的分裂和合并,会影响效率

创建索引原则

1、不要在离散度很低的列上创建索引,如百分之90的数据都是相同的,在这种字段上创建索引会导致经过一次索引扫描只能排除到很少量的数据,导致性能并没有太大提升

2、索引的列不应该太多,索引太多也会对增删改数据的性能降低,而且会占用太多磁盘空间

3、联合索引,当两个字段A和B,大多数查询时使用到B字段时一般都会基于字段A,那么就没有必要为B字段单独创建索引,使用联合索引更合适

4、主键最好使用有序的id,避免page的分裂和合并影响性能

以上便是笔者对索引的一些理解。