资列页(16kb大小)的结构有7个部分
1.使用者纪录(user records)
2.空闲空间(free space)
3.页面中最小与最大的纪录(infimum+supermum)
4.页面目录(page directory)
5.页面表头(page header)
6.档案表头(file header)
7.档案结尾(file trailer)
前文提到前三个的部分,今天会当作大家已经熟悉前面的内容,继续说明剩下的部分,在过程中如有不清楚的地方就再回去复习吧。
根据之前的学习我们已经知道资料页的结构是一个按照主键大小排序的单向链结串列。
此时我们想要查询资料的话,最直观且最差的做法就是一笔一笔依序查询,当资料页有n笔我们新增的纪录,那就查询n次吧...
大家应该都认同这不是一个好的解法,我们来学习Innodb的工程师是怎麽设计的
设计的思维就像是我们在看一本书时,最前面会有各章节的页码,透过其我们可以知道要查询的内容从那一页开始找比较快。
Innodb的工程师就是这样针对所有纪录去分组(就像书的各章节)并定义各组的槽(就像章节的页码)。
具体的作法细节如下:
分组有一个规定,infimum纪录所在的组只有它自己一笔纪录,supermum纪录所在的组包含它自己只能有1到8笔纪录,其余的组别则为4到8笔纪录。
这边进一步补充说明前面第一点分组的细节
举一个例子来说明:
现有16笔纪录
mysql> insert into ryan_demo2_table(c1,c2,c3) values (1,100,'a'),(2,200,'b'),(3,300,'c'),(4,400,'d'),(5,500,'e'),(6,600,'f'),(7,700,'g'),(8,800,'h'),(9,900,'i'),(10,1000,'j'),(11,1100,'k'),(12,1200,'l'),(13,1300,'m'),(14,1400,'n'),(15,1500,'o'),(16,1600,'p');
Query OK, 16 rows affected (0.01 sec)
Records: 16 Duplicates: 0 Warnings: 0
mysql> select * from ryan_demo2_table;
+------+------+------+
| c1 | c2 | c3 |
+------+------+------+
| 1 | 100 | a |
| 2 | 200 | b |
| 3 | 300 | c |
| 4 | 400 | d |
| 5 | 500 | e |
| 6 | 600 | f |
| 7 | 700 | g |
| 8 | 800 | h |
| 9 | 900 | i |
| 10 | 1000 | j |
| 11 | 1100 | k |
| 12 | 1200 | l |
| 13 | 1300 | m |
| 14 | 1400 | n |
| 15 | 1500 | o |
| 16 | 1600 | p |
+------+------+------+
16 rows in set (0.01 sec)
其实在资料页里面有18笔纪录(包含自动建立的infimum跟supermum纪录)
而这里的分组会是(以c1栏位主键值来看)
infimum纪录自己1组(槽0 对应的主键值为infimum)
1、2、3、4四笔1组(槽1 对应的主键值为4)
5、6、7、8四笔1组(槽2 对应的主键值为8)
9、10、11、12四笔1组(槽3 对应的主键值为12)
13、14、15、16四笔纪录跟supermum纪录1组(槽4 对应的主键值为supermum)
总共5组
在这样的情境下,我们想搜寻一笔主键值为6的纪录,搜寻的过程会是以下这样的。
1.一开始low为0,high为4,计算中间槽的位置(0+4)/2=2,查看槽2对应的主键值为8,因爲6小於8,所以high变为2(界限缩小),而low不变一样为0
2.重新计算中间槽的位置(0+2)/2=1,查看槽1对应的主键值为4,因为6大於4,所以low为1(界限缩小),而high不变一样为2
3.因为high-low为1,表示要搜寻的纪录就在槽2的组别里面,这时只要找到槽2主键值最小的那一笔纪录,沿着单向链结串列历遍槽2的所有纪录即可找到我们要的纪录
本来要比对16次的纪录变成只要历遍5,6就找到6了,就算不幸为此组最後一笔,1组纪录笔数最多为8笔,因此最多也就8次,大大的提升了搜寻的速度。
Innodb为了想得到资料页的纪录状态定义了页面标头,方便知道情况。
这边总共有14个状态(占用固定56位元组)但我不会全部列出来,我觉得现在看也看不懂的就不赘述了,等未来有遇到再来补充大家也比较清楚。我这边就特别提几个应该要知道且实用的状态。
前面的页面表头是纪录资料页的各种状态,而档案表头则不局限於资料页,包含了其他各种类型页面的纪录状态。这里一样只说明几个比较重要的状态。
我们知道Innodb会先把资料从磁碟读取到记忆体去更新(因为磁碟速度太慢),更新完毕後在刷新回磁碟。
但如果在记忆体更新後,发生意外(断电等),导致没有刷新回磁碟,两边资料不一致的bug就尴尬了。
所以Innodb在每个页的尾部增加了档案结尾的部分。占8位元组包含两个部分(校正码4位元组及最後被修改时对应的LSN的後4位元组[LSN是新名词之後会再说明,先大概知道有这东西就好])。
透过比对档案表头与档案结尾的校正码及LSN验证来确保资料成功刷新。
今天的内容较多,但这些都是基础且很重要的东西,大家要好好熟悉,因为这对接下来要说明的内容都是必要的前提知识。在一起好好加油吧~耶~吃苍蝇去!
>>: Day 07-Terraform 写起来不够 DRY 的问题,这解 Terragrunt 你试试看
VS Code组合键真的非常多,才发现每天抽空的时间没办法练习完,重新编辑分成『介面操作』和『文字编...
本系列文章同步发布於笔者网站 上一篇介绍了 Neutron 的网路的概念,接下来将会接续介绍 Neu...
前言 一开始是为了一些蠢事而做的,至於是什麽蠢事,这边就暂且不提,後来自己看见Meet6机器人的强大...
阿嬷都看得懂的 CodePen 怎麽用 VSCode 已经很棒了,不过最近比较流行的是云端协作。以目...
由於在未来的专案有机会使用到 Bootstrap,所以就藉这个机会来介绍一下如何在 Angular ...