MySQL总结(三)

MySQL总结(三)存储

InnoDB底层是以页为最小单位和内存进行IO的

如下图所示:页(page)存的是一行行的记录,大小是16KB,页与页之间在磁盘上不是相邻的,它们之间通过双向链表连接

区(extent)存的是64个页,大小是64*16KB = 1MB,为什么要有区,为了减少随机IO

段(segment)有64个区,段是数据库中的分配单位,不同类型的数据库对象以不同的段形式存在。创建表和索引时就会创建对应的表段和索引段。

表空间(tablespace)由一个及以上的的段组成,一个段只能所属于一个表空间 pChzMct.png

页的内部结构

七部分组成

pChz1nf.png
pChz1nf.png

1.File Header

有几个属性

  • FIL_PAGE_OFFSET(4字节)

    这个是唯一标识一个页的

  • FIL_PAGE_TYPE (2字节)

    一共有一下几种类型

pChzqCd.png
pChzqCd.png
  • FIL_PAGE_PREV 和 FIL_PAGE_NEXT(都为4字节)

    页和页之间是双向链表,这两个属性连接

  • FILE_PAGE_SPACE_OR_CHECKSUM (4字节)

    校验和就是通过Hash算法将一个字符串算为一个比较短的字符,比较的时候如果CHENKSUM都不一样,就没必要比较全部的字符串了。

    磁盘与内存就是通过页进行IO的,如果IO到一半,服务器宕机了,那怎么判断这页内容是不是合适的呢?

    头和尾都有这个属性,如果校验和不相等就要重新IO

  • FIL_PAGE_LSN (4字节)

    页被修改后的日志序列位置 (Log Sequence Number)

2. File trailer (8字节)

  • FIL_PAGE_SPACE_OR_CHECKSUM 和File Header一样
  • FIL_PAGE_LSN(4字节)

3.Free space

每加入一条记录,在Free Space中申请空间,然后记录,等到这一部分没有了,就说明这一页满了,需要申请新的页了

pChzOgI.png
pChzOgI.png

4.user records

会按照指定的行格式(后边会介绍)进行记录

5.Infimum和supermum

最大记录和最小记录

6.page directory 页目录

为什么要有页目录?

因为数据之间是通过单向链表连接的,查询速度很慢。所以可以考虑建立一个目录,用二分来提高查询效率

会把数据分组,第一组是一个记录(最小的记录),最后一组1-8个数据,其他有4-8个数据

下边就是一个页目录,槽里边存的是地址偏移量,指向组内的最大的数据。

图里面的记录头信息只有n_owned和next_record

可以看到只有组内的最后一个数据有值,表示当前组的有多少数据

pC4SpVS.png
pC4SpVS.png

如果要查id = 6的,

槽 low = 0,hight = 4,二分 m = 2,指向的数据是8, 6 < 8;

low 不变, hight - 1,二分 m = 1,指向的数据是 4, 6 > 4;

因为这时候 hight - low = 1, 所以数据就是在第二组的第二条。

为什么就直接知道数据在第二组的第二条,因为,第一组的最大时4,我们很容易知道下一组的最小是什么,然后既可以遍历2次。

pC4S9Ug.png
pC4S9Ug.png

7.page header

为了能得到一个数据页中存储的记录的状态信息,比如本页中已经存储了多少条记录,第一条记录的地址是什么,页目录中存储了多少个槽等等,特意在页中定义了一个叫Page Header的部分,这个部分占用固定的56个字节,专门存储各种状态信息。

pChzzb8.png
pChzzb8.png

行格式

1.Compact

见下图

  • 边长字段列表

    varchar等类型的记录是不定长的,所以需要一个值来说明它到底有多长,而且它是逆序存的

    如c1,c2,c3,如果长度分别3,5,1;那么存储的就是1,3,5;

    为什么要逆序呢?

    记录头信息中有指向下一条记录的指针;正好指向真实数据和记录头信息中间的位置,这样往右就是真实数据,往左就是记录头信息,比较方便。

pChzL8A.png
pChzL8A.png
  • NULL值列表

    如果某一列的值可能为null,那么null值怎么存呢?

    有一个字段专门来记录,NULL 是1,NOT NULL 0;

    也是逆序存放的

  • 记录头信息

    有一下几个属性

  • 1.delete_mask

    一条记录删除了之后,不会立即从磁盘删除,是吧这个字段的值标记为1

  • 2.min_rec_mask

    最小的记录

  • 3.n_owned

    页目录中每个组中最后一条记录的头信息中会存储该组一共有多少条记录,作为 n_owned 字段。

    其他的记录为0。

  • 4.heap_no

    记录当前记录在本页中的位置

    最小最大记录在 0 1,我们插入的数据在后边

  • 5.record_type

    0:表示普通记录 1:表示B+树非叶节点记录 2:表示最小记录 3:表示最大记录

  • 6.next_recorde

    下一条记录的偏移量

pChzvKP.png
pChzvKP.png

除了真实数据和以上的属性,还有3个字段

row_id 如果没有主键,没有索引,会自动使用这个字段建立索引

transaction_id

roll_point pChzH4H.png

实际上这几个列的真正名称其实是:DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR。 一个表没有手动定义主键,则会选取一个Unique键作为主键,如果连Unique键都没有定义的话,则会为表默认添加一个名为row_id的隐藏列作为主键。所以row_id是在没有自定义主键以及Unique键的情况下才会存在的。

2.DynamicCompressed

  • 行溢出

在Compact和Reduntant行格式中,对于占用存储空间非常大的列,在记录的真实数据处只会存储该列的一部分数据,把剩余的数据分散存储在几个其他的页中进行分页存储,然后记录的真实数据处用20个字节存储指向这些页的地址(当然这20个字节中还包括这些分散在其他页面中的数据的占用的字节数),从而可以找到剩余数据所在的页。 pChzXvt.png

  • DynamicCompressed的行格式

    在MySQL 8.0中,默认行格式就是Dynamic,Dynamic、Compressed行格式和Compact行格式挺像,只不过在处理行溢出数据时有分歧:

    Compressed和Dynamic两种记录格式对于存放在BLOB中的数据采用了完全的行溢出的方式。如图,在数据页中只存放20个字节的指针(溢出页的地址),实际的数据都存放在Off Page(溢出页)中。

    pChzxDf.png
    pChzxDf.png

    Compressed行记录格式的另一个功能就是,存储在其中的行数据会以zlib的算法进行压缩,因此对于BLOB、TEXT、VARCHAR这类大长度类型的数据能够进行非常有效的存储。

    Compact和Redundant两种格式会在记录的真实数据处存储一部分数据(存放768个前缀字节)。

3.Redundant

  • 字段偏移列表

    少了“变长”两个字:Redundant行格式会把该条记录中所有列(包括隐藏列)的长度信息都按照逆序存储到字段长度偏移列表。

本文由 mdnice 多平台发布

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值