MySQL -- 数据页

作者: sunyelw | 来源:发表于2019-07-06 16:42 被阅读0次

    前言

    最近在学MySQL,决定记录一下,能写多少写多少,不定时更新,加油。

    正文

    分几个部分来吧,大致如下:

    • 字符集与比较规则

    • 行格式与数据页

    • InnoDB索引

    • 访问方法与连接

    • explain 与 子查询优化

    • redoundo 日志

    • MVCC 与 锁

    本文为第二部分 第二节 数据页


    上回说的单条记录没有挑战,下面开启多条记录的处理--数据页

    数据页的秘密其实在前面我们说到的记录头的几个属性里面已经说了一点了,比如分组、单链表、最小记录、最大记录、B+树索引、叶子节点等。

    那么,让我们继续“脱衣服”~


    数据页结构

    图片来源网络
    名称 中文名 占用空间大小 简单描述
    File Header 文件头部 38字节 页的一些通用信息
    Page Header 页面头部 56字节 数据页专有的一些信息
    Infimum + Supremum 最小记录和最大记录 26字节 两个虚拟的行记录
    User Records 用户记录 不确定 实际存储的行记录内容
    Free Space 空闲空间 不确定 页中尚未使用的空间
    Page Directory 页面目录 不确定 页中的某些记录的相对位置
    File Trailer 文件尾部 8字节 校验页是否完整

    简单的介绍一下这些属性中的重要的东西

    Infimum + Supremum
    • 这个值位于整个页面的第三部分
    • 分别是最小记录和最大记录,属于MySQL为每个页添加的虚拟记录
    • 由五个字节的记录头 和 八个字节的 值(分别是单词InfimumSupremum)组成
    • 最小记录的记录头中heap_no为0
    • 最大记录的记录头中heap_no为1
    • 也就是说正式记录中的heap_no属性从2开始
    • 最小记录的record_type 是2
    • 最大记录的record_type 是3
    • 最小记录是页中单链表的头结点
    • 最大记录是页中单链表的尾结点

    Page Directory

    • 这个页目录里面存的是一个一个的槽(slot)
    • 每个槽指向组内最大记录的地址偏移量(我理解为页内偏移量)
    • 这个数据结构是数组,按主键值从小到大排列
    • 这种结构注定了查询最快的方式是二分法,时间复杂度O(lgN)
    • 页分裂(前面说过) 时会增加一个槽

    User RecordsFree Space

    • 完全空闲的页是没有 User Records部分的
    • 插入数据时,从Free Space分配空间给User Records,直到Free Space没有空间或空间不够分配新的记录,这时需要申请新的页

    Page Header

    名称 占用空间大小 描述
    PAGE_N_DIR_SLOTS 2字节 在页目录中的槽数量
    PAGE_HEAP_TOP 2字节 还未使用的空间最小地址,也就是说从该地址之后就是Free Space
    PAGE_N_HEAP 2字节 本页中的记录的数量(包括最小和最大记录以及标记为删除的记录)
    PAGE_FREE 2字节 第一个已经标记为删除的记录地址(各个已删除的记录通过next_record也会组成一个单链表,这个单链表中的记录可以被重新利用)
    PAGE_GARBAGE 2字节 已删除记录占用的字节数
    PAGE_LAST_INSERT 2字节 最后插入记录的位置
    PAGE_DIRECTION 2字节 记录插入的方向
    PAGE_N_DIRECTION 2字节 一个方向连续插入的记录数量
    PAGE_N_RECS 2字节 该页中记录的数量(不包括最小和最大记录以及被标记为删除的记录)
    PAGE_MAX_TRX_ID 8字节 修改当前页的最大事务ID,该值仅在二级索引中定义
    PAGE_LEVEL 2字节 当前页在B+树中所处的层级
    PAGE_INDEX_ID 8字节 索引ID,表示当前页属于哪个索引
    PAGE_BTR_SEG_LEAF 10字节 B+树叶子段的头部信息,仅在B+树的Root页定义
    PAGE_BTR_SEG_TOP 10字节 B+树非叶子段的头部信息,仅在B+树的Root页定义

    1.PAGE_GARBAGE

    • 在页面空间不够时,会尝试将所需空间与这个值比较,如果够,那么将记录移到临时表中,再重新插回来(记录逐条新增是不会产生碎片空间的),但很明显,这很耗性能
    1. PAGE_BTR_SEG_LEAFPAGE_BTR_SEG_TOP
    • 后面会说到段的概念,一个索引会有两个段,一个叶子节点段,一个非叶子节点段,这两个属性分别代表一个 Segment Header,代表了哪个表空间哪个页面的哪个INODE Entry (表空间号 + 页面号 + 偏移量值)

    File Header

    名称 占用空间大小 描述
    FIL_PAGE_SPACE_OR_CHKSUM 4字节 页的校验和(checksum值)
    FIL_PAGE_OFFSET 4字节 页号
    FIL_PAGE_PREV 4字节 上一个页的页号
    FIL_PAGE_NEXT 4字节 下一个页的页号
    FIL_PAGE_LSN 8字节 页面被最后修改时对应的日志序列位置(英文名是:Log Sequence Number)
    FIL_PAGE_TYPE 2字节 该页的类型
    FIL_PAGE_FILE_FLUSH_LSN 8字节 仅在系统表空间的一个页中定义,代表文件至少被刷新到了对应的LSN值
    FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 4字节 页属于哪个表空间

    这个属性里面的值就说三个:

    • FIL_PAGE_OFFSET
    1. 每个表空间的页号唯一,四个字节足够用了
    • FIL_PAGE_PREVFIL_PAGE_NEXT
    1. 上一页和下一页,诶哟,这不是双向链表啊,那所有的页加起来组成了一个双向链表哇,好玩吧~
    • FIL_PAGE_TYPE
    类型名称 十六进制 描述
    FIL_PAGE_TYPE_ALLOCATED 0x0000 最新分配,还没使用
    FIL_PAGE_UNDO_LOG 0x0002 Undo日志页
    FIL_PAGE_INODE 0x0003 段信息节点
    FIL_PAGE_IBUF_FREE_LIST 0x0004 Insert Buffer空闲列表
    FIL_PAGE_IBUF_BITMAP 0x0005 Insert Buffer位图
    FIL_PAGE_TYPE_SYS 0x0006 系统页
    FIL_PAGE_TYPE_TRX_SYS 0x0007 事务系统数据
    FIL_PAGE_TYPE_FSP_HDR 0x0008 表空间头部信息
    FIL_PAGE_TYPE_XDES 0x0009 扩展描述页
    FIL_PAGE_TYPE_BLOB 0x000A BLOB页
    FIL_PAGE_INDEX 0x45BF 索引页,也就是我们所说的数据页

    现在只需要看这最后一个索引页,又称数据页(跟InnoDB的特性有关)

    属性介绍了一堆,还是不知道怎么查,举个栗子

    • 假设一条查询语句定位到了这个页面
    • 先将条件中的列(加深为col)与值(假设为x)拎出来,二分法定位在哪个组。
    1. 假设10个槽,(0 + 9)/2 = 4, 将第四个槽的条件列的值拿出来跟x比较,如果x大,那就从5~9的槽中继续二分找;如果x小, 那就从0~4的槽中继续二分;
    2. 直到前后两个槽相差为1,那记录就在那个大的槽里面,又每个槽其实存的是组内最大记录,那前一个槽对应记录的下一个节点就是目标槽对应组中的最小值,顺着单链表往后一个一个比就完事了,每组最多八条记录,这速度还是很快的。

    没明白就多看两遍~

    相关文章

      网友评论

        本文标题:MySQL -- 数据页

        本文链接:https://www.haomeiwen.com/subject/ngbphctx.html