MySQL:InnoDB的页合并与页分裂到底是什么( 二 )


MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
每个叶子节点都有着一个指向包含下一条(顺序)记录的页的指针,这也是InnoDB可以实现自顶向下的遍历和叶子节点顺序范围扫描的能力基础 。
4 页合并(page merging)当执行数据行删除时,并没有物理删除 , 而是将改行数据标记(flaged)为删除,允许被其他记录声明使用 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
当页中删除的记录达到MERGE_THRESHOLD(默认页体积的50%),InnoDB确认最靠近的前后页是否页达到MERGE_THRESHOLD,如果也已经在限定值之下,可以将两个页进行合并优化空间使用 。如上图,当page#5数据小于50%时,由于page#6数据量也是小于50%,因此会进行页合并,合并后,page#6就会变为空页,可以接纳新数据 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
在delete/update语句操作中都可能会诱发页合并的发生,关联到当前页的相邻页 。如果页合并成功 , 在INFOMATION_SCHEMA.INNODB_METRICS中的index_page_merge_successful将会增加 。
5 页分裂(Page Splits)假设有如下场景,page#10已经被填满时,继续插入数据 , #10没有足够空间去容纳新的记录,根据“下一页”逻辑 , 记录应该由page#11负责,但是页#11也已经满了 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
这时候的简化逻辑为:
  1. 创建新页#12;
  2. 判断当前页(page#10)可以从哪里进行分裂(记录行里面);
  3. 移动记录行;
  4. 重新定义页与页之间的关系;

MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
新的页#12被创建 。
MySQL:InnoDB的页合并与页分裂到底是什么

文章插图
图片
此时的页与页之间的关系为:
  • Page #10 will have Prev=9 and Next=12
  • Page #12 Prev=10 and Next=11
  • Page #11 Prev=12 and Next=13(page#13是后续顺序插入新增的页);
这样,B+树水平方向的逻辑一致性仍然满足,但是在物理存储上页可能是乱序的,大概率会落到不同的区 。
不太清楚这里是否会有疑问 , page#10和page#11虽然都已经写满,但是可能已经存在page#12,并且还有大量剩余空间,为什么不做数据迁移呢?这样不就可以不插入新页而导致大量的空间浪费了吗?
虽然从理论上是可行的,但是在实操中 , 这时候InnoDB就需要先遍历确认next page是否有空余位置,甚至是继续遍历直至找到有空余位置的页 , 然后进行数据迁移,这个操作可能带来大量遍历的时间复杂度以及数据复制的IO操作,因此,方案不可行 。
因此,我们可以总结:页分裂可能发生在执行插入或者更新时,但是可能也会造成页的错位(dislocation),即落入不同的区 。
InnoDB用INFORMATION_SCHEMA.INNODB_METRICS表来跟踪页的分裂数 。可以查看其中的index_page_splits和index_page_reorg_attempts/successful统计 。
当page#12和page#10的数据都低于MERGE_THRESHOLD时 , 这时候可以通过页合并将数据合并回来 。
另一种方式是使用OPTIMIZE重新整理表,可以将大量分布在不同区的页理顺 , 因此,也是一个很重量级和耗时的过程 。
同时,不管是页分裂还是页合并 , InnoDB都会在索引树上加写锁(x-latch) 。在操作频繁的系统中这会是在隐患,可能会导致索引的锁竞争(index latch contention) 。如果表中没有合并和分裂操作(也就是写操作),称之为“乐观(optimistic)”更新 , 只需要使用读锁(S) 。带有合并或者分裂的操作称之为“悲观(pessimistic)”更新,使用写锁(X) 。

【MySQL:InnoDB的页合并与页分裂到底是什么】


推荐阅读