暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL InnoDB记录存储结构

snaily 2021-04-07
957

 InnoDB
将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,页的大小一般为 16 KB。


行格式:我们平时以记录为单位向表中插入数据,这些记录在磁盘上的存放方式被称为行格式
或者记录格式


InnoDB
存储引擎行格式类型: Compact
Redundant
Dynamic
Compressed


在创建或修改表的语句中指定行格式

    CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称


    ALTER TABLE 表名 ROW_FORMAT=行格式名称


    COMPACT行格式


    一条完整的记录分为两大部分:记录的额外信息
    记录的真实数据


    记录的额外信息

    包括三部分: 变长字段长度列表, NULL值列表, 记录头信息


    变长字段长度列表

    变长字段VARCHAR(M)
    VARBINARY(M)
    、各种TEXT
    类型,各种BLOB
    类型,由于存储多少字节的数据是不固定的,所以在存储真实数据的时候需要把这些数据占用的字节数也存起来
    这些变长字段占用的存储空间分为两部分:真实数据真实数据占用的字节数


    Compact
    行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,形成一个变长字段长度列表,各变长字段数据占用的字节数按照数据表中列的顺序逆序存放


    存储真实数据占用的字需要占用的存储空间的计算规则:

    先假设一下变量: 

    1. 字符集中表示一个字符最多需要使用的字节数(SHOW CHARSET
    语句的结果中的Maxlen
    )为
    W

    2. 符集中最多存储M
    个字符该字符集能表示的字符串最多占用的字节数就是M×W

    3. 真实数据字符串占用的字节数为L


    计算方法: 


    • M×W <= 255
      ,使用1个字节存储真实数据占用的字节数

    •  当M×W > 255
      ,分为两种情况: 如果L <= 127
      ,使用1个字节存储真实数据占用的字节数,如果L > 127
      ,则用2个字节存储真实数据占用的字节数


    注意: 

     1. 变长字段长度列表中不储存值为 NULL 的列内容占用的实际长度

     2. 如果数据表中没有变长字段则不需要变长字段长度列表

     3. 对于CHAR(M) 类型的列,当列采用的是定长字符集时,该列占用的字节数不会被加到变长字段长度列表,而如果采用变长字符集时,该列占用的字节数也会被加到变长字段长度列表

     

    NULL值列表

    表中的某些列可能存储NULL
    Compact
    行格式把值为NULL
    的列统一管理起来,存储到NULL
    值列表中每个允许存储NULL
    的列对应一个二进制位,二进制位按照表中列的顺序
    逆序排列,二进制位的值为1
    ,代表该列的值为NULL
    ,二进制位的值为0
    ,代表该列的值不为NULL


    注意:

    • 不允许存储NULL
      的列,不会加入
      NULL值列表,如: 主键列、被NOT NULL
      修饰的列

    • MySQL
      规定存储NULL值列表
      的最小单位是字节,如果允许存储NULL
      的列数不足8位,则在字节的高位补
      0


    记录头信息

    记录头信息
    由固定的5
    个字节组成5
    个字节也就是40
    个二进制位,不同的位代表不同的意思,如图:


    记录的真实数据

    记录的真实数据
    除了我们自己定义的列的数据以外,MySQL
    会为每条记录默认添隐藏列
    ,具体如下:

    列名是否必须占用空间描述
    row_id6
    字节
    行ID,唯一标识一条记录
    transaction_id6
    字节
    事务ID
    roll_pointer7
    字节
    回滚指针

    这几个列的真正名称分别是:DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR


    InnoDB
    数据表主键生成策略:优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个Unique
    键作为主键,如果表中连Unique
    都没有,则InnoDB
    会为表默认添加一个名为row_id
    的隐藏列作为主键。InnoDB存储引擎会为每条记录都添加 transaction_id 和 roll_pointer 这两个列,但是 row_id 是可选的(在没有自定义主键以及Unique键的情况下才会添加该列)


    注意: 如果列的值为NULL
    ,它们被存储在记录的额外信息NULL值列表
    处,在记录的真实数据处不再冗余存储,从而节省存储空间。


    行溢出数据


    VARCHAR(M)最多能存储的数据

    MySQL
    对一条记录占用的最大存储空间是有限制的,除了
    BLOB
    或者TEXT
    类型的列之外,其他所有的列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过65535
    个字节


    存储一个VARCHAR(M)
    类型的列,其实需要占用3部分存储空间:

    • 真实数据

    • 真实数据占用字节的长度

    • NULL
      值标识,如果该有NOT NULL
      属性则没有这部分存储空间


    如果使用的是ascii
    字符集(一个字符只占用1个字节):

    1. 没有NOT NULL
    属性,最多存储65532
    个字节的数据,真实数据的长度占用2个字节,NULL
    值标识需要占用1个字节

    2. 有NOT NULL
    属性,最多只能存储65533
    个字节的数据,真实数据的长度占用2个字节,不需要NULL
    值标识


    如果使用的是ascii
    字符集(一个字符可能占用多个字节):

    1. 没有NOT NULL
    属性

    gbk
    字符集表示一个字符最多需要2
    个字节,最多能存储32766
    (65532/2)字符

    utf8
    字符集表示一个字符最多需要3
    个字节,最多能存储21844
    (65532/3)个字符

    2. NOT NULL
    属性

    gbk
    字符集表示一个字符最多需要2
    个字节,最多能存储32766
    (65533/2)个字符

    utf8
    字符集表示一个字符最多需要3
    个字节,最多能存储21844
    (65533/3)个字符


    上述情况都是在表中只有一个字段的情况下,实际上一个行中的所有列(不包括隐藏列和记录头信息)占用的字节长度加起来不能超过65535个字节!


    记录中的数据太多产生的溢出

    MySQL

    为基本单位来管理存储空间,记录数据都会被分配到某个
    中存储一个页的大小是16KB
    (16384
    字节)
    一个VARCHAR(M)
    类型的列就最多可以存储65532
    个字节,这样就可能造成一个页存放不了一条记录的尴尬情况。



    Compact
    Redundant
    行格式中,如果某一列中的数据非常多的话,在本记录的真实数据处只会存储该列的前768
    个字节的数据和一个指向其他页的地址,然后把剩下的数据存放到其他页中,这个过程也叫做行溢出
    ,存储超出768
    字节的那些页面也被称为溢出页
    简图如下:

    不只是 VARCHAR(M) 类型的列,其他的 TEXTBLOB 类型的列在存储数据非常多的时候也会发生行溢出


    Dynamic和Compressed行格式

    这俩行格式和Compact
    行格式挺像,只不过在处理行溢出
    数据时不同,它们不会在记录的真实数据处存储字段真实数据的前768
    个字节,而是把所有的字节都存储到其他页面中,只在记录的真实数据处存储其他页面的地址,简图如下:

    Compressed
    行格式和Dynamic
    不同的一点是,Compressed
    行格式会采用压缩算法对页面进行压缩,以节省空间。

    最后修改时间:2021-04-07 14:51:07
    文章转载自snaily,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

    评论