写本文的起因

《MySQL是怎样运行的》于2020年11.1日发行至今近一年的时间mysql列拼接,已经印刷近两万册,十分感谢各位小伙伴的捧场。不过最近在答疑群里一直有小伙伴说:“书看的时候很爽,以为自己啥都会了,不过过一段时间后就都忘了,面试一问好像都学过,但是就是想不起来具体的内容是个啥”。

小孩子在这里需要强调一下,这不是一本入门的书籍,不是随便翻翻就可以学会,需要大家拿出一个完整的时间,找一个笔记本好好记一下笔记才可以学会的。

另外,书里涉及大量的细节,比方说我们致力于将记录、页面、索引、表空间中涉及的结构的每一个字节都是干什么的给大家讲清楚,但记住这些细节并不是重点,细节是用来辅助大家理解脉络的。大家如果不清楚脉络而只纠结于细节中,那会让自己看上去很累,但过一周之后就啥也不记得了。

本文来尝试以最简单的脉络来帮各位理出一条线,大家有了这条线作为主心骨,就不用怕淹没在细节的海洋中无法自拔了。

第1~2章

前两章非常简单,主要介绍如何启动MySQL服务器和客户端,以及启动选项和系统变量。没有什么难度,就不花篇幅唠叨了。

第3章

我们需要明白“字符”是面向人类的概念,计算机需要用一个二进制字节序列来表示字符,由于二进制字节序列和字符的映射关系谁都可以规定,所以市面上产生了各种各样的字符集。

数字之间可以比较大小,字符之间也可以比较大小,不过比较字符时取决于人的好恶。比方说有人觉得’A’和’a’是相等的,有人就觉得不相等。所以我们在比较字符前需要事先规定好一个规则来说明谁大谁小,这个规则就是所谓的比较规则。

MySQL支持若干种字符集,不同字符集也可以有不同的比较规则,我们可以通过一定语法来进行配置。

第4章

大家需要知道一条记录实际上是分两部分存储的:

mysql 逗号拼接_mysql列拼接_mysql存储过程字符串拼接

重点需要知道在记录的额外信息中有一个两字节的称为next_record指针,通过该指针各条记录可以组成一个单向链表:

mysql 逗号拼接_mysql列拼接_mysql存储过程字符串拼接

单向链表中的记录的主键值是按照从小到大的顺序排序的,也就是说这个单向链表是有序的。

第5章

大家需要知道记录是放在页里边的, InnoDB是以页为单位从磁盘上加载数据的。页面可以配置成4KB、8KB、16KB、32KB、64KB几种大小,不过默认是16KB的。

对于存储记录的数据页来说,它的结构如下图所示:

mysql列拼接_mysql 逗号拼接_mysql存储过程字符串拼接

下边假设某个页中存储了16条用户插入的记录,该数据页的效果图如下所示:

其中Infimum记录和Supremum记录是InnoDB给我们自动生成的两个伪记录,并且规定:

•Infimum记录作为本页面中最小的记录

•Supremum记录作为本页面中最大的记录

如上图所示,各条记录之间按照主键值大小组成了一个单向链表。

接下来我们面临的问题是如何从一个按照主键值大小进行排序的单向链表中快速定位到指定的主键值在哪里。很遗憾,链表做不到呀~

为了解决快速搜索的问题,设计InnoDB的大叔引入了一个称作页目录的东西。具体的做法就是将单向链表中的记录分成若干个组,如下图所示:

mysql存储过程字符串拼接_mysql 逗号拼接_mysql列拼接

然后将把每个组最大的那条记录在页面中的地址(就是距离页面第0个字节处的偏移量)取出来单独放到页面中的一个部分。每个地址占用2个字节,多个地址就可以组成一个数组结构,如下图所示:

可见,页目录本质上就是一个指针数组,指针指向的记录是有序的,我们就可以针对这个页目录进行二分搜索。比方说我们想找主键值为6的记录,那就可以通过页目录先进行二分查找,定位到主键值6其实是在第3组里,然后再遍历第3组中的记录,就可以定位到具体的主键值6的记录在哪里了。

稍微总结一下,通过第5章的学习,我们应该知道如何在单个页面中快速定位某个主键值的记录了,大致分两步:

•第一步:通过页目录定位到该记录所在的组。

•第二部:遍历该组中的记录来找到待查询的主键值(由于一个组中最多有8条记录,所以遍历一个组中的记录的代价还是很小的)。

第6章

现在大家已经知道如何在单个页面中通过页目录来快速定位某个主键值对应的记录了。

一个页里可以放置若干条记录,如果记录太多,就得分散到不同的页中。

页中存储的除了记录以外,还有若干额外信息,其中包括两个指针(这两个指针在上图中的File Header中):

•一个指针指向上一个页•一个指针指向下一个页

这样多个页之间也可以通过双向链表连接起来,而且InnoDB会保证每个页中存储记录的主键值肯定不大于下一个页中存储记录的主键值mysql列拼接,也就是说由页面组成的双向链表也是按照它们中存储记录的主键值大小进行排序的。

现在我们做一个大胆的假设:假设一个页里只能存储4条记录,然后有16条记录分散在4个页里,页之间按照它们中存储的主键值进行排序为双向链表,如下图所示:

mysql列拼接_mysql 逗号拼接_mysql存储过程字符串拼接

现在如果我们想查找主键值为6的记录该怎么办呢?很遗憾,我们不知道主键值为6的记录在哪个页里,只能从第一个页开始,一个页一个页的找。

遍历很低效,InnoDB采取的方案就是将每个页的主键值最小的用户插入的记录的主键值拿出来,然后和该页的页号拼接成一个新的记录,为了和用户插入的记录做区分,我们把用户插入的记录称作用户记录,把这个新拼接成的记录称作目录项记录。

目录项记录也按照主键值排序成单向链表,也可以通过页目录来快速定位主键值等于某个值的目录项记录。

mysql存储过程字符串拼接_mysql列拼接_mysql 逗号拼接

引入了目录项记录以及存储目录项记录的页之后,我们再查找主键值为6的记录就分为2步了:

•先在存储目录项记录的页中通过页目录进行二分查找,快速定位用户记录所在的页。因为5 < 6 < 9,我们就知道了主键值为6的用户记录是在主键值为5的目录项记录所指向的页中。

•然后在主键值为5的目录项记录所指向的页中,再通过页目录进行二分查找快速定位到主键值为6的用户记录。

表中的记录是可以不断扩充的,每增加一个存储用户记录的页,就需要在存储目录项记录的页中增加一条目录项记录,而页的大小是有限的(默认是16KB),所以存储目录项记录的页也可能被填满,这时候就需要再申请新的存储目录项记录的页,如下图所示:

mysql存储过程字符串拼接_mysql列拼接_mysql 逗号拼接

多个存储目录项记录的页之间也是用双向链表连接的,而且它们也是按照各自页中目录项记录的主键值进行排序的。但是对于多个存储目录项记录的页来说,我们怎么知道我们要找的记录应该在哪个存储目录项记录的页中呢?

这时设计InnoDB的大叔开始了套娃操作,即再将各个存储目录项记录的页中最小的主键值给提取出来,与相应的页号组成更高一层的目录项记录,再填充到新的页里,如下图所示:

mysql 逗号拼接_mysql存储过程字符串拼接_mysql列拼接

更高一层的目录项记录也按照主键值大小连成了单向链表,这些更高一层的目录项记录所在的页中也有页目录结构。

这样的话各个页面就分为了3层。设计InnoDB的大叔把最下边的存放用户记录的一层称作第0层,第0层往上是第1层,再往上是第2层。

现在如果我们想查找主键值为6的记录的话,那么查找过程就分为了3步:

•第1步:先通过第二层页面的页目录进行二分查找,可以快速定位到第1层目录项记录所在的页。因为1 < 6 < 17,我们就知道我们该去第1层中的最左边的那个页中进行进一步的查找。

•第2步:在第1层的存储目录项记录的页中通过页目录进行二分查找,快速定位用户记录所在的页。因为5 < 6 < 9,我们就知道了主键值为6的用户记录是在主键值为5的目录项记录所指向的页中。

•第3步:然后在主键值为5的目录项记录所指向的页中,再通过页目录进行二分查找快速定位到主键值为6的用户记录。

设计InnoDB的大叔给上边的结构给了个名:B+树(因为像一颗倒过来的树)。InnoDB中的B+树还有另一个别名:索引。B+树的第0层,也就是最下边那层的页面称作叶子节点,其余的页面被称作非叶子节点或者内节点。其中最高层的节点也被称作根节点或者根页面。

至此,我们了解了索引结构是如何诞生的。

上边介绍按照主键进行排序的B+树索引结构被称作聚簇索引,聚簇索引的叶子节点存放着完整的用户记录(即各个列的值)。我们也可以给自己感兴趣的列或者列组合建立B+树索引,不过此时B+树中就会按照我们给定的列或列组合进行排序(这里指的是每一层页面的排序以及页面中记录的排序),我们把这种给自己感兴趣的列建立的索引称作二级索引或者辅助索引。二级索引的叶子节点中只存放建立索引时指定的列的值以及该记录对应的主键值。

小结一下

下边的小结并不仅仅针对聚簇索引,也针对二级索引。我们将用键值来表示聚簇索引中的主键值或者二级索引中的二级索引列值。

1.记录是按照键值大小组成一个单向链表的。

2.记录是被存放在页面中的,页面中维护着一个页目录结构,通过页目录可以对键值进行二分查找,从而加快在单个页面中的查询速度。

3.多个页面可以按照键值大小组成双向链表,为了快速定位到需查找的键值在哪个页面中,我们引入了目录项记录以及存储目录项记录的页。

4.存储目录项记录的页大小也有限,我们引入了更高层次的目录项记录,从而形成了套娃结构。我们把这个套娃结构称作B+树,也就是InnoDB中的索引。

好了,前6章的整体脉络就是上边这些了,大家抓住这些主线,然后进行针对性的阅读,补充更多的细节。一旦理解了这个脉络,之后想忘也忘不掉了。

看在小孩子码了这么多字儿的面子上,点个在看/赞 再走呗>_>

推广一下自己的书>_>

没有看过小孩子的《MySQL是怎样运行的》小伙伴可以从京东当当淘宝找一下哈,下边贴一个当当链接(长按扫描二维码),目前五折哦~

小青蛙历史文章