「SQL」拜托,别再问我什么是 B+ 树了( 四 )


「SQL」拜托,别再问我什么是 B+ 树了
本文插图
如果把 3604 这个身份证号插入到 3504 后面的话 , 这个节点的元素个数就有 3 个了 , 显然不符合二叉树的条件 , 此时就会造成页分裂 , 就需要调整这个节点以让它符合二叉树的条件 。
「SQL」拜托,别再问我什么是 B+ 树了
本文插图
如图示:调整过后符合二叉树条件
这种由于页分裂造成的调整必然导致性能的下降 , 尤其是以身份证作为主键的话 , 由于身份证的随机性 , 必然造成大量的随机结点中的插入 , 进而造成大量的页分裂 , 进而造成性能的急剧下降 , 那如果是以自增 id 作为主键呢 , 由于新插入的表中生成的 id 比索引中所有的值都大 , 所以它要么合到已存在的节点(元素个数未满)中 , 要么放入新建的节点中(如下图示)所以如果是以自增 id 作为主键 , 就不存在页分裂的问题了 , 推荐!

「SQL」拜托,别再问我什么是 B+ 树了
本文插图
有页分裂就必然有页合并 , 什么时候会发生页合并呢 , 当删除表记录的时候 , 索引也要删除 , 此时就有可能发生页合并 , 如图示:
「SQL」拜托,别再问我什么是 B+ 树了
本文插图
当我们删除 id 为 7 , 9 对应行的时候 , 上图中的索引就要更新 , 把 7 , 9 删掉 , 此时 8 , 10 就应该合到一个节点 , 不然 8 , 10 分散在两个节点上 , 可能造成两次 IO 读 , 势必会影响查找效率! 那什么时候会发生页合并呢 , 我们可以定个阈值 , 比如对于 N 叉树来说 , 当节点的个数小于 N/2 的时候就应该和附近的节点合并 , 不过需要注意的是合并后节点里的元素大小可能会超过 N , 造成页分裂 , 需要再对父节点等进行调整以让它满足 N 叉树的条件 。

「SQL」拜托,别再问我什么是 B+ 树了
本文插图
怎么根据索引查找行记录 相信大家看完以上的 B+ 树索引的介绍应该还有个疑惑 , 怎么根据对应的索引值查找行记录呢 , 其实相应的行记录就放在最后的叶子节点中 , 找到了索引值 , 也就找到了行记录 。 如图示:
「SQL」拜托,别再问我什么是 B+ 树了
本文插图
可以看到 , 非叶子节点只存了索引值 , 只在最后一行才存放了行记录 , 这样极大地减小了索引了大小 , 而且只要找到索引值就找到了行记录 , 也提升了效率 ,
这种在叶节点存放一整行记录的索引被称为聚簇索引 , 其他的就称为非聚簇索引 。
「SQL」拜托,别再问我什么是 B+ 树了
本文插图
关于 B+ 树的总结 综上所述 , B+树有以下特点:

  • 每个节点中子节点的个数不能超过 N , 也不能小于 N/2(不然会造成页分裂或页合并)
  • 根节点的子节点个数可以不超过 m/2 , 这是一个例外
  • m 叉树只存储索引 , 并不真正存储数据 , 只有最后一行的叶子节点存储行数据 。
  • 通过链表将叶子节点串联在一起 , 这样可以方便按区间查找
本文由日常中常用的 SQL 由浅入深地总结了 B+ 树的特点 , 相信大家应该对 B+ 树索引有了比较清晰地认识 , 所以说为啥我们要掌握底层原来 , 学完了 B+ 树 , 再看开头提的几个问题 , 其实也不过如此 , 深挖底层 , 有时候确实能让你以不变应万变 。
「SQL」拜托,别再问我什么是 B+ 树了