MySQL-数据行

seefly 2021年07月04日 13次浏览

MySql工作原理

MySQL 是怎样运行的:从根儿上理解 MySQL 学习笔记

字符串中最长的不重复子串

一、Inodb存储引擎

1、数据存储方式

mysql以页为单位和磁盘进行交互,每次最少读取或者写入一页的数据,一页数据默认大小为16kb,数据在页中是以行为单位进行存储,在msql中有下面几种行格式。

COMPACT行格式

image-20210429220936055

  • 变长字段长度列表

    由于我们可以使用varchar(n)来声明一个列的数据类型,那么这个列在实际使用过程中的所占用的大小是根据所用字符集编码和实际存储的字符个数来决定的,比如使用ASCII来存储5个字符,那么该列当前最多就占用 5byte,如果我们使用UTF8来存储的话实际情况可能有不一样,例如汉字可能占用两个字节,也可能占用三个字节。所以就需要记录每个列实际占用了多少字节

    • 逆序记录每列实际长度

    • 忽略定长列

    • 忽略为Null的列

    • 记录这些可变长度本身也需要存储空间,对于每列用1byte记录还是2byte记录,计算公式为

      if(字符集最大字节数 * 变长列声明的最大长度 > 255){
        if(该列实际占用的字节数 > 127){
          使用2byte记录该变长列占用字节数
        }
      }else {
        使用1byte记录该变长列占用字节数
      }
      
  • Null值列表

    对于可以为Null的列需要维护一个额外信息标记该列是否为null

    • 逆序记录可以为null的列的实际null情况,1表示该列为null,0表示不为null
    • 忽略不能为null的列
  • 记录头信息

    记录头信息由5个字节即40bit组成

    • 2 bit预留位,未使用
    • delete_mask ,1bit,删除标志位
    • min_rec_mask,1bit,B+树中非叶子节点最小记录该标志位为1
    • n_owned,4bit,当前记录拥有的记录数
    • heap_no,13bit,当前记录在堆中的位置信息
    • record_type3bit,记录类型
    • next_record16bit,下一条记录的相对位置
  • 隐藏的数据

    • row_id,6byte,没有主键也没有唯一列,就会生成这个
    • transaction_id,事务id
    • roll_pointer,回滚指针

image-20210429222617724

Compact下的Char(n)列

​ 对于char(10)这种形式声明的列,并且使用ASCII来编码,那么就算你只存了一个a那么也会用空格补齐9个字符,最后占用10字节。如果使用UTF8来编码(每个字符最少1byte,最大3byte),我们可能会占用10~30个字节,默认也会分配至少10个字节。

二、Redundant行格式

目前只有部分系统表中使用这种数据行

image-20210430093725901

  • 字段长度偏移列表

    • 逆序记录每列结束位置,包括row_id等
    • 使用1byte还是2byte存储记录值,取决于数据中是否有一列长度(byte)大于127
    • 最高位1表示当前列为null,否则不是null,这也解释了1byte只能表示127长度的原因
    • 定长列,即使为null也要记录偏移量,因为它实际占用空间

    image-20210430095436359

  • 记录头信息

image-20210430095634391

  • Redundant下的Char(n)

    一刀切的形式,使用ASCII则该列占用 1*n byte,使用utf8则占用3*n byte。简单明了,就给你最大的不会产生不够用的情况。

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

​ Mysql规定一行数据(不包括text,blob)最多占用65535个字节;

对于varchar(m)最多能放多少字符这一点取决于当前表中有多少列,以及他们的编码方式。极限情况下

表中只有一列,

  • 编码方式ASCII,这个时候可以使用65535byte - 2byte - 1byte = 65532byte,也就是65532个ascii,其中2个变长记录信息,1个null列信息。
  • 编码方式UTF8,(65535byte - 2byte - 1byte) / 3 = 21844个UTF8字符,3的意思你明白吧?就是UTF8的最大占用字节数

表中有多列

  • 综上所述,一行数据最大不能超过65535byte,自己算

四、溢出数据

一个页默认是16kb也就是16384个字节,但是一个varchar最多能够放65535个字节,所以会导致某一列太大造成溢出的情况。

  • 如何存储溢出的数据?

    • 在本列数据中只记录前768字节的数据,并使用20字节记录溢出数据的地址和溢出长度
    • 存储溢出行的地方叫做溢出页
  • 什么时候发生溢出?

    对于只有一个列的表来说使用这个公式计算

    132 + 2×(27 + n) < 16384
    
    • 132表示当前页需要的记录的一些基本信息
    • 2的意思就是,mysql规定一页必须至少有两行数据
    • 27表示记录头+变长信息+null列信息+row_id啥的
    • 16384就是16kb,也就是一页大小
  • 多列情况

    实际情况一个表肯定不止一列,多列的话就要根据实际情况计算了

五、Dynamic和Compressed行格式

  • 除了处理溢出数据有区别,其他基本一样
  • 数据溢出的时候记录数据的地方不再放任何数据信息,只放溢出数据的地址