MySQL · 引擎特性 · InnoDB 数据页解析 (3)

更新PAGE_LAST_INSERT,PAGE_DIRECTION,PAGE_N_DIRECTION,设置这些参数后,可以一定程度上提高连续插入的性能,因为插入前需要先定位插入的位置,有了这些信息可以加快查找。详见查找记录代码分析。

修改数据目录。因为增加了一条新的记录,可能有些目录own的记录数量超过了最大值(目前是8条),需要重新整理一下这个数据页的目录(page_dir_split_slot)。算法比较简单,就是找到中间节点,然后用这个中间节点重新构建一个新的目录,为了给这个新的目录腾空间,需要把后续的所有目录都平移,这个涉及一次momove操作(page_dir_split_slot和page_dir_add_slot)。

写redolog日志,持久化操作。

如果有blob字段,则处理独立的off-page。

删除记录

注意这里的删除操作是指真正的删除物理记录,而不是标记记录为delete-mark。核心函数入口函数在page_cur_delete_rec。步骤如下:

如果需要删除的记录是这个数据页的最后一个记录,那么直接把这个数据页重新初始化成空页(page_create_empty)即可。

如果不是最后一条,就走正常路径。首先记录redolog日志。

重置PAGE_LAST_INSERT和递增block的modify clock。后者主要是为了让乐观的查询失效。

找到需要删除记录的前驱和后继记录,然后修改指针,使前驱直接指向后继。这样记录的链表上就没有这条记录了。

如果一个目录指向这条被删除的记录,那么让这个目录指向删除记录的前驱,同时减少这个目录own的记录数。

如果这个记录有blob的off-page,则删除。

把记录放到PAGE_FREE链表头部,然后递增PAGE_GARBAGE的大小,减小PAGE_N_RECS用户记录的值。

由于第五步中递减了own值,可能导致own的记录数小于最小值(目前是4条)。所以需要重新均衡目录,可能需要删除某些目录(page_dir_balance_slot)。具体算法也比较简单,首先判断是否可以从周围的目录中挪一条记录过来,如果可以直接调整一下前后目录的指针即可。这种简单的调整要求被挪出记录的目录own的记录数量足够多,如果也没有足够的记录,就需要删除其中一个目录,然后把后面的目录都向前平移(page_dir_delete_slot)。

查找记录/定位位置

在InnoDB中,需要查找某条件记录,需要调用函数page_cur_search_with_match,但如果需要定位某个位置,例如大于某条记录的第一条记录,也需要使用同一个函数。定位的位置有PAGE_CUR_G,PAGE_CUR_GE,PAGE_CUR_L,PAGE_CUR_LE四种,分别表示大于,大于等于,小于,小于等于四种位置。
由于数据页目录的存在,查找和定位就相对简单,先用二分查找,定位周边的两个目录,然后再用线性查找的方式定位最终的记录或者位置。
此外,由于每次插入前,都需要调用这个函数确定插入位置,为了提高效率,InnoDB针对按照主键顺序插入的场景做了一个小小的优化。因为如果按照主键顺序插入的话,能保证每次都插入在这个数据页的最后,所以只需要直接把位置直接定位在数据页的最后(PAGE_LAST_INSERT)就可以了。至于怎么判断当前是否按照主键顺序插入,就依赖PAGE_N_DIRECTION,PAGE_LAST_INSERT,PAGE_DIRECTION这几个信息了,目前的代码中要求满足5个条件:

当前的数据页是叶子节点

位置查询模式为PAGE_CUR_LE

相同方向的插入已经大于3了(page_header_get_field(page, PAGE_N_DIRECTION) > 3)

最后插入的记录的偏移量为空(page_header_get_ptr(page, PAGE_LAST_INSERT) != 0)

从右边插入的(page_header_get_field(page, PAGE_DIRECTION) == PAGE_RIGHT)

其他函数

除了插入删除查找外,还有一些函数也比较重要,例如:
page_create,创建新的空页的时候,都需要调用这个函数来初始化元信息。
page_move_rec_list_end,当数据页需要重组时候,需要把数据从一个数据页拷贝到另外一个,这个时候就需要用到。类似的还有函数page_move_rec_list_start,两个函数的拷贝方式不同,一个是从头开始拷贝到指定的记录,另外一个是从指定记录开始拷贝到数据页最后。
page_validate,这种函数主要是debug模式下校验数据页是否损坏的检验函数,不做什么实际工作,但是这些函数非常时候初学者阅读,能快读的理解数据页的结构。
page_cur_open_on_rnd_user_rec,这函数是把位置放到一个随机的记录上,当change buffer的B树满的时候,目前的逻辑是随机选一条记录,进行合并。

数据页Corruption

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxdxg.html