MySQL 索引

B树与B+树

首先,索引是一种数据结构,它的目的是加速数据查找效率,具备高效查找效率的数据结构都可以作为索引。比如通过新华词典查汉字,会先通过目录查偏旁部首,然后会得到目标汉字所在页数。这里的目录就是一种索引。

在数据库中,大部分数据是存于磁盘的,我们都知道磁盘随机读写效率很差,因此需要更好的存储方式来提高性能瓶颈。可以快速查找的数据结构不多,常见的有hash表、B树、平衡树、B+树。

如何存储数据?

如果设计一种简单的存储方式,我们可以像新华词典一样,在内存中记录数据在磁盘存储位置(使用平衡树),进行随机读取。它有一些缺点,首先是必须在内存存储数据索引,内存空间是数据量的瓶颈。其次它面多大量随机读,效率很低。因此,如果想要我们的DB能承载海量数据,就必须将索引移动到磁盘中存储,减少对内存的依赖。

如果我们在磁盘中存储平衡树是什么样子?

首先操作系统操作磁盘的方式是按页读写,即操作系统每次读取一页数据进入内存,我们对内存的该页数据读写,该页数据变为脏页,再由操作系统写回磁盘。在内存中,平衡树的每个节点可能占十几个字节,假设一页是4KB(这与操作系统有关),那需要多页存储一颗完整的平衡树,同时平衡树的旋转是整棵树的操作,这是就需要将所有存储平衡树的页都调入内存进行修改。可见该方案维护成本太大,且效率低下。

B-Tree

由于数据读写的粒度是一页,那么我们以页为单位,将树的节点看作一页,当节点的一页数据填满,再创建节点填充下一页。同时平衡树的性能瓶颈在于它的高度,这一缺点在磁盘上被放大,高度意味着需要调取页的次数,因此高度需要降低。

因此B树诞生了,B树是多路平衡查找树。简单的说:每个节点中的数据是有序的,除叶子节点外,每个节点存储有N个数据和N+1个子节点,数据两两之间成为一段区间;每个节点的子节点个数> max(2, [m/2]),m是B的阶;所有叶子节点处于同一水平。(关于B树更详细的介绍可以看这篇博文:https://www.cnblogs.com/lianzhilei/p/11250589.html)

B树的优势在于:

  1. 高度降低,节点中数据有序,整体查找时间近似logn
  2. 每次调取一页,适应局部性原理
  3. 每个节点中同时存放key和key相关的value,最快O(1)命中

B+Tree

B+Tree可以看做B树的改进:

  1. 每个节点有N个key值,和N个子节点。(B树是N+1)
  2. B+树中只有叶子节点才会存储实际data,其他节点只存储key值,用作索引。(这一点和跳表有点相似,底层是一层链表,上层对链表中的每一项做了索引,以达到快速找到底层节点的目的)
  3. 叶子节点包含全部键值信息,且有序排列。

B+树对比B树的优势在于:

  1. B+树的查找效率更稳定,必须查找到叶子节点。
  2. B+树叶子节点相连,范围查找能力很强,找到边界直接顺序遍历链表即可。
  3. 由于非叶子节点只作为索引,所以可以存储更多的元素,因此IO效率更高。(元素更多意味着区间划分越细,定位区间更准确,因此减少页调页)

索引分类

在MyISAM中,索引和数据作为两个文件单独存放,索引文件后缀为.MYI),数据文件后缀为.MYD。B+树索引的叶子节点存放的不是实际data,而是data在数据文件中的位置。而InnoDB中,索引和数据存放在一个文件中(.ibd),每张表对应一个.ibd文件,B+树的叶子节点存放的就是实际data。

主键索引

一张表只能有一个主键,该列字段数据唯一且不为NULL。

二级索引(辅助索引)

辅助索引和数据存放于不同文件,辅助索引也是B+树存储,其叶子节点存储的不是data所在地址,而是索引字段的主键。需要去数据文件通过主键在查询一遍。

  1. 唯一索引
  2. 普通索引
  3. 联合索引
  4. 前缀索引
  5. 全文索引

聚簇索引与非聚簇索引

所谓聚簇索引就是B+树叶子节点中存放的是实际数据,就像InnoDB的存储方式;非聚簇索引是B+树叶子节点存放指向实际数据位置的指针,就像二级索引和MyISAM的存储方式。

索引的使用

SQL优化方式

1、开启SQL慢查询日志
2、查询慢日志中的SQL语句,使用explain分析索引使用情况
3、show profile命令可更精准的体现该SQL命令的资源使用情况以及耗时

索引的使用注意事项

1、索引个数限制。索引并不是越多越好,一张表中建议不超过5个。因为索引本身也占资源,再者数据的更新需要维护索引
2、组合索引字段个数限制。单个组合索引字段数不允许超过5个
3、组合索引的前缀匹配规则。索引尽量建在where后面经常使用的字段上,参考索引作用的第一条
4、order by语句需要遵循前缀匹配规则。
5、索引字段值尽量不重复。索引必须建立在离散程度大的列上,比如身份证号、员工工号等,而不是性别、职位等字段,因为性别、职位等字段重复值太多,筛选度低
6、尽量使用主键查询。而不是其他索引,因为主键查询不会触发回表查询
7、使用group by语句时,尽量先过滤再分组。即把条件写在where子句里而不是having子句

索引失效的情况:
1、禁止在select语句后面使用*,而是写出具体要返回的列
2、当使用索引列进行查询的时候尽量不要使用表达式
3、模糊列不能以%开头进行查询
4、范围列可以用到索引,但是范围列后面的列无法用到索引,包括:<、<=、>、>=、between

参考:
https://blog.csdn.net/Baisitao_/article/details/104267080
https://blog.csdn.net/u010648555/article/details/81102957

posted @ 2022-01-16 00:00  moon_orange  阅读(23)  评论(0编辑  收藏  举报