前言

  大家好,我是xicheng。从这篇文章开始,会陆续地更新MySQL相干的相干文章。帮忙大家晋升根底的同时,顺便就筹备了面试的八股文,开始发车。

常见存储引擎

  在讲InnoDB之前先看一下MySQL有哪些常见的存储引擎。

  InnoDB:反对事务,行锁设计,反对外键,通过MVCC获取高并发性,5.5.8开始成为MySQL的默认存储引擎。提供插入缓存,二次写,自适应哈希索引,预读等高性能,高可用性能。次要面向OLTP(在线事务处理)利用。表都是依据主键程序组织寄存的,这种形式叫索引组织表。

  MyISAM:不反对事务,存储引擎表由MYD与MYI组成,前者存储数据文件,后者存储索引文件。次要面向OLAP(联机剖析解决)利用。

  Memory:数据放内存中,速度十分快,只反对表锁,并发性能差,索引默认应用哈希索引。

  Archive:只反对SELECT与INSERT。适宜存储归档数据。

  NDB:集群存储引擎,数据全放内存中,JOIN操作是在Server层实现而不是存储引擎层。

  Federated:不存放数据,指向近程数据库上的表。只反对MySQL数据库表,不反对其它数据库的表。

抉择适合的存储引擎

  须要反对事务,热备份,疾速的解体复原就抉择InnoDB。

  不须要反对事务,根本只有INSERT与SELECT,例如日志表。能够抉择MyISAM。

行格局

  包含COMPACT,REDUNDANT,DYNAMIC(MySQL8.0默认格局),COMPRESSED

  InnoDB1.0.x版本的文件格式定义为Barracuda,之前的版本定义为Antelope。Barracuda文件格式蕴含了Antelope文件格式,并引入了DYNAMIC,COMPRESSED两种行格局。如下图所示。

COMPACT

行构造示意图

  • 变长字段长度列表

    • 存的是各变长字段的实在数据占用的字节数。并按字段程序逆序寄存。
    • 当maxlen (可变字段一个字符所需的字节数) * m(该字段最多存储的字符数) > 255,且L(实在存的字节数)> 127时,变长字段应用2字节记录长度。否则应用一个字节记录长度。
  • NULL值列表

    • 每列占用一个二进制位,依照字段程序逆序排序,值为1示意该列的值为NULL。值为0示意该列的值不为NULL。
    • NULL值列表必须用整数字节示意,若应用的二进制位数有余整数字节时,则在高位补0。
  • 记录头信息,固定由5个字节组成,如下表所示。
名称大小(位)形容
预留位11没有应用
预留位21没有应用
deleted_flag1标识该条记录是否被删除
min_rec_flag1B+树中每层非叶子节点的最小的目录项都会增加该标记
n_owned41页记录会被分为若干组,每组中有一条记录的该值代表该组中所有记录的条数。其余记录的该值为0
heap_no13以后记录在页面堆中的绝对地位
record_type30:一般记录,1:B+树非叶子节点的目录条数,2:Infimum记录(下边界,记录比该页中任何主键值都要小的值),3:Supremum记录(上边界,记录比该页中任何主键值都要大的值,形成了页中记录的边界)
next_record16从以后记录的实在数据到下⼀条记录的实在数据的地址偏移量。这样向左读取就是记录头信息,向右读取就是实在数据。

行记录的实在数据

  除了有用户定义的列外,还有若干暗藏列,如下表所示。

列名是否必须大小(字节)形容
DB_ROW_ID6行id。如果⽤户没有定义主键,则取⼀个Unique键作为主键,如果表中无Unique键,InnoDB会默认增加⼀个DB_ROW_ID暗藏列作为主键
DB_TRX_ID6事务idDB_ROLL_PTR是7回滚指针
DB_ROLL_PTR7回滚指针

  行记录的实在数据的程序一次是:DB_ROW_ID,DB_TRX_ID,DB_ROLL_PTR,用户定义的列1的值,用户定义的列2的值,...,用户定义的列n的值。其余行格局的实在数据也是这个程序。

CHAR存储格局

  当采纳定长编码的字符集时,该列用的字节数不会被加到变长字段长度列表中。采纳变长编码的字符集时,则会加到其中。

  采纳变长编码字符集时,CHAR(M)至多会占用M个字节。

REDUNDANT

行构造示意图

行记录的额定信息

  • 字段长度偏移列表

      依照相邻两个偏移量的差值来计算各个列值的长度。并按字段程序逆序寄存。

      比方,某一行的字段长度偏移列表为 18 15 0D 07 ,因为是逆序寄存的,则按列排序就是 07 0D 15 18。

    • 第1列长度就是0x07个字节,即7个字节。
    • 第2列长度就是(0x0D - 0x07)个字节,即6个字节。
    • 第3列长度就是(0x15 - 0x0D)个字节,即8个字节。
    • 第3列长度就是(0x18 - 0x15)个字节,即3个字节。
  • 记录头信息,固定由6个字节组成,如下表所示。
名称大小(位)形容
预留位11没有应用
预留位21没有应用
deleted_flag1标识该条记录是否被删除
min_rec_flag1B+树中每层非叶子节点的最小的目录项都会增加该标记
n_owned41页记录会被分为若干组,每组中有一条记录的该值代表该组中所有记录的条数。其余记录的该值为0
heap_no13以后记录在页面堆中的绝对地位
n_field10记录中列的数量
byte_offs_flag1标记字段长度偏移列表中每个列对应的偏移量应用一个字节还是两个字节来示意
实在数据占用空间大小为n
当n<=127时,值为1,用1个字节示意偏移量
当127<n<=2^15^ 时,值为0,用2个字节示意偏移量
当n>2^15^ 时,值为0,记录的一部分已放入溢出区,用2个字节示意偏移量
next_record16从以后记录的实在数据到下⼀条记录的实在数据的地址偏移量。这样向左读取就是记录头信息,向右读取就是实在数据
  • NULL值解决

      如果列对应的偏移量值的第1个比特位为1,则该列值就是NULL,否则就不是NULL。

      如果存储NULL值的字段是定长类型,如CHAR(M),则字段对应的实在数据会应用0填充。

      如果存储NULL值的字段是变长类型,如VARCHAR(M),则不在行记录的实在局部占用任何的存储空间。

    CHAR存储格局

      CHAR(M)占用空间 = 该字符集示意一个字符最多须要的字节数 * M。例如,utf-8的CHAR(10)占用30个字节。gbk的CHAR(10)占用20个字节。

溢出列

  构造示意图如下。

  每页额定须要132个字节存储其它数据。每条记录须要固定用27个字节存储存储额定信息。

  每页至多须要存2条记录。则有如下不等式:132 + 2 * (27 + n) < 16KB。解出n < 8099。当这列中存储的数据占用空间>=8099字节时,就会成为溢出列。

DYNAMIC

  与COMPACT相似,区别是,解决溢出列时,会把该列的所有数据都存到溢出列中。

COMPRESSED

  与DYNAMIC相似,区别是,会采纳压缩算法对页面进行压缩。

结尾

  MySQL通过InnoDB的记录行开了个头,心愿大家能继续关注上来。下一篇MySQL文章讲InnoDB-数据页的存储构造。

微信扫描下方二维码,或搜寻“xicheng”,关注公众号后回复【笔记】,有我筹备的15万字Java面试笔记。


  感激各位人才的点赞、珍藏和评论,干货文章继续更新中,下篇文章再见!