字节二面你知道InnoDB行记录存储结构吗?

程序员常用的IDEA插件:https://github.com/silently9527/Toolkit

前言

我们平时在向MySQL数据库表中插入数据时,实际数据是以行记录的格式存储在磁盘上的,本篇我们就一起来详细的了解下MySQL的行记录格式,理解了行记录的格式有助于我们后面了解MySQL如何快速在页中定位出行记录,以及MySQL的版本控制链,事务隔离级别等等,行记录格式是许多MySQL核心知识的基础。

InnoDB行记录类型

MySQL中总共提供了四种类型的行格式:Compact,Redundant,Dynamic,Compressed

在创建表或修改表的时候可以指定行记录的格式
create table 表名 row_format=行格式名
alter table 表名 row_format=行格式名

知道就行,不需要去记住,基本上使用不到

Compact行格式

在四种类型的行格式中,我们主要来学习Compact格式,其他格式的行记录类似;

image

从图中我们可以看出行记录主要是由4部分组成:变长字段长度、Null值列表,行记录头信息以及列的真实数据

变长字段长度列表

在MySQL中很一些变长的数据类型(varchar,text等),MySQL需要知道这些数据的实际长度,这样才能正确的在真实数据中取出对应列的数据,所以变长字段是由两部分组成:

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

每个变长字段的长度要么用1字节要么用2字节表示,由此就决定了每个字段的最大字节数是65535;

  • 假如字符类型若为gbk,每个字符最多占2个字节,最大长度不能超过32766;
  • 假如字符类型若为utf8,每个字符最多占3个字节,最大长度不能超过21845。

那到底什么时候选用1字节什么时候选用2字节呢?

这里需要定义三个变量:w,m,l

  1. 假如使用的字符集是utf8mb4,每个字符占用的字节数是4字节,那么w=4;假如字符类型若为utf8,每个字符最多占3个字节,那么w=3; 所以w表示字符集中每个字符所占的字节数
  2. varchr(m),这里m表示的是定义的字符的长度
  3. l 表示的是该字段真实数据占用的字节数

m*w <= 255;表示该字段定义的最大长度都不会超过1字节,那么该字段的长度就用1字节表示

m*w > 255 && l<=127; 表示该字段定义的长度可能会超过1个字节,但是当前的实际长度是小于127的,可以用1个字节表示

m*w > 255 && l>127; 用2字节来表示该字段的长度

思考:为什么与l比较的值是127呢?
当我们定义的变长字段可能大于255(也就是超过一个字节)时,MySQL如何才能知道当前读取的字节该字段的完成字段长度,还是该字段的半个字段长度,为了解决这个问题,MySQL使用了1字节的首位,当首位为0表示当前是1字节,当首位为0表示当前长度是2字节;由于占用了1字节的首位,所以剩下7位所能表示的最大值是127

变长字段不会存储为Null列的长度;其次并不是行记录中一定需要变长字段长度这段内容,如果行记录中没有定义变长字段或者是变长字段都为Null,那么就不会有变长字段长度这部分

变长字段占用的字节数按照顺序逆序存储

Null值列表

一条记录中某些列通常可能允许为null,所以Compact行格式把这些允许为null的进行了统一管理;

  1. 首先统计出表中定义的哪些列允许为null
  2. 如果表中的字段都不能为空,那么就不存在null值列表;如果存在允许为null的字段,那么就按照字段的顺序为每个字段对应一个二进制位,当二进制位为1时表示该列值为空;当二进制位位0时表示该列值不为空
  3. Null值列表必须有整数个字节来表示,所以对应没有占用的位使用0补位
image

行记录的头信息

头信息中主要包含了6个字段,其中5个字段也是在面试中经常被问到的,为了方便记忆,我们把5个字段对应到手的5根指头:

  • n_owned(拇指): 一个数据页会被分成很多个组,每组最后的一条记录该字段为1,其他记录该字段为0,就像分组中所有的记录的大哥;(对应拇指)

  • deleted_flag(食指): 标记该记录是被删除的;当记录被删除时不会真实删除,而是用该字段标记,并且把所有删除的记录使用链表连接起来,以后的文章会继续说到这个字段。(想象下你平时挖鼻屎是不是用的食指)

  • heap_no(中指): 表示当前记录在数据页中的相对位置(MySQL使用该字段来表示记录位置,可以和中指对应,不可描述)

  • record_type(无名指): 表示当前记录属于哪种类型,(无名指用来带戒指的,与分类有关,可以把人分为已婚和未婚,)

    1. 0表示普通记录
    2. 1表示目录项记录,索引中非叶子结点中的数据记录都是1
    3. 2表示infrmum记录,每个数据页中至少会有两条记录,其中最小记录的record_type=2
    4. 3表示Supremum记录,每个数据页中至少会有两条记录,其中最大记录的record_type=3
  • next_record(小拇指): 存放下一条记录的相对位置(当数数时,左手的小拇指数完之后就该换右手了,和next_record表达的意思类型)

最后一个字段min_rec_flag : B+树中每层非叶子结点最小目录项记录该字段为1;该字段相对于其他5个字段显得不那么重要,不会影响理解B+树索引

隐藏列

除了用户自定义的数据列以外,MySQL还会为每行记录生成3个隐藏列

  • row_id: 行ID,记录的唯一标识;当用户在表中定义了主键字段就优先选择用户定义的主键,如果没有,就查找是否有定义不为null的唯一索引,如果有就把该列作为主键,如果没有MySQL就会生成一列row_id隐藏列作为主键
  • trx_id: 事务的ID;该字段对于实现一致性视图和事务隔离级别至关重要,以后会详细说明
  • roll_pointer: 回滚指针,指向的是该记录的上一个版本号,MySQL的MVCC主要就是通过这个字段来实现的。

溢出列

MySQL中所有的行记录都会被存储在数据页中,每个数据页的大小是16KB,也就是16384个字节;在前面我们讲过变长字段的长度可以用两个字节来表示,所以列的最大长度可以是65535,当遇到这种极端情况时,一个数据页是存储不下这一条记录的。

Compact行格式针对这种情况的处理方式是在真实的数据处记录该列的一部分数据(768字节),其他多余的数据会存储到新的数据页中(溢出页),然后在该记录中使用20个字节存储这些数据页的地址

image

溢出页与溢出页之间使用的链表相连接

其他的行记录格式:

Redundant:MySQL5.0之前的格式,直接忽略

Dynamic,CompressedCompact很像,只是在溢出列的处理有些差异,他们只会在真实数据列中使用20个字节存储溢出页的地址

面试题

  • char(M)定义的字段,在变长字段的长度列表中会记录该字段的长度吗?

欢迎大家在评论区留言讨论


最后(点关注,不迷路)

文中或许会存在或多或少的不足、错误之处,有建议或者意见也非常欢迎大家在评论交流。

最后,写作不易,请不要白嫖我哟,希望朋友们可以点赞评论关注三连,因为这些就是我分享的全部动力来源🙏

image
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容