索引和B+树

索引和B+树

前言

  • 为啥索引常用 B+ 树作为底层的数据结构
  • 除了 B+ 树索引,你还知道什么索引
  • 为啥推荐自增 id 作为主键,自建主键不行吗
  • 什么是页分裂,页合并
  • 怎么根据索引查找行记录

定义问题

  • 日常需求
    • 根据用户id查用户信息
    • 根据区间值去查找用户信息
    • 按id逆序排列,分页取出用户信息
  • 索引需满足的条件
    • 根据某值精确快速查询
    • 根据区间值的上下界来快速查找此区间的数据
    • 索引值需要拍好顺序,支持快速顺序查找和逆序查找

几种常见的数据结构对比

散列表(哈希表)

  • 根据关键码值而直接进行访问的数据结构,可以让码值经过哈希函数的转换映射到散列表对应的位置上,查找效率高。

  • 对于每一行数据,会对所有的索引列计算一个哈希码,散列表里的每个元素执行数据行的指针,由于索引自身只存储对于的哈希值,所以索引结构十分紧凑。

  • 劣势:

    • 针对哈希索引,只有精确匹配索引所有列的查询才有效, 比如我再列(A,B)上建立哈希索引,如果只查询数据类A,则无法使用。
    • 无法用于排序,无法根据区间快速查找,因为并不是按照索引值顺序存储的
    • 希索引只包含哈希值和行指针,不存储字段值,所以不能使用索引中的值来避免读取行,不过,由于哈希索引多数是在内存中完成的,大部分情况下这一点不是问题
    • 哈希索引只支持等值比较查询,包括 =,IN(),不支持任何范围的查找,如 age > 17

链表

  • 双向链表支持顺序查找和逆序查找,但是不支持按照某个值或区间的快速查找。
  • 索引需要及时插入更新,链表也不支持数据的快速插入
跳表

在链表的基础上加上多层索引构成的

基本可以满足我们的需求,并且已经和B+树十分接近了。

B+树

平衡二叉树

  • 性质
    • 若左子树不空,则左子树上所有节点的值均小于它的根节点的值
    • 若右子树不空,则右子树上所有节点的值均大于或等于它的根节点的值
    • 每个非叶子节点的左右子树的绝对高度之差的绝对值(平衡因子)最多为1
    • 查找节点的时间复杂度O(log2n)

B+树

  • 和平衡二叉树的主要区别就是所有的节点值都在最后叶节点上用双向链表连接在一起。
  • 但是数据量大的时候容易造成内存爆炸,所以将其放到磁盘中,但是会导致由于内存读取速度和磁盘的相差太大,导致速度大幅度降低
  • 为了解决这个问题可以使用五叉树…
  • 页:操作系统按页的大小进行读取的(页大小通常为 4 kb),磁盘每次读取都会预读,会提前将连续的数据读入内存中,这样就避免了多次 IO,即局部性原理,即我用到一块数据,很大可能这块数据附近的数据也会被用到,干脆一起加载,省得多次 IO 拖慢速度, 这个连续数据有多大呢,必须是是操作系统页大小的整数倍,这个连续数据就是 MySQL 的页,默认值为 16 KB,也就是说对于 B+ 树的节点,最好设置成页的大小(16 KB),这样一个 B+ 树上的节点就只会有一次 IO 读。
  • 但是页不能太大,InnoDB是通过内存中缓存池来管理从磁盘中读取的页数据的。页太大的话,很快就把这个缓存池撑满了,可能会造成页在内存与磁盘间频繁换入换出,影响性能。
  • 所以N叉树中的N应该设为,尽可能保证每个节点的大小等于一个页的大小。

页分裂与页合并

  • 推荐使用自增id作为主键,自建主键不推荐
  • B+树为了维护索引的有序性,每插入或更新一条记录的时候,会对索引进行更新。
  • 增加节点的时候容易造成页分裂,需要调整这个节点让它复核二叉树的条件,但是页分裂对导致性能下降。
  • 而id自增由于插入的都是最大值,要么合到已存在的节点,要么放到新建的节点中,不存在也分裂
  • 页合并也是同样的。

根据索引查找行记录

  • 由于对应的行记录就放在最后的叶子节点中,所以找到了索引值也就找到了行记录。
  • 非叶子结点值存了索引值,只在最后一行才存放了行记录,这样极大的减少了索引行大小,而且只要找到索引值就找到了行记录,也提高了效率
  • 在叶子节点存放一整行记录的索引被称为聚簇索引,其他的称为非聚簇索引。

B+树总结

  • 每个节点中子节点的个数不能超过 N,也不能小于 N/2(不然会造成页分裂或页合并)
  • 根节点的子节点个数可以不超过 m/2,这是一个例外
  • m 叉树只存储索引,并不真正存储数据,只有最后一行的叶子节点存储行数据。
    点的个数不能超过 N,也不能小于 N/2(不然会造成页分裂或页合并)
  • 根节点的子节点个数可以不超过 m/2,这是一个例外
  • m 叉树只存储索引,并不真正存储数据,只有最后一行的叶子节点存储行数据。
  • 通过链表将叶子节点串联在一起,这样可以方便按区间查找

猜你喜欢

转载自blog.csdn.net/issunmingzhi/article/details/105247445