MySQL是怎样运行的
字符集和比较规则
字符集
计算机中只能存储二进制数据,那怎么存储字符呢?建立字符与二进制数据之间的映射关系就行了。
一个字符映射成一个二进制数据的过程叫做编码,反之叫做解码。
比如’a’ -> 00000001 (十六进制:0x01)这样的映射关系。人们将这样的映射关系抽象出一个字符集的概念来描述某个字符范围的编码规则。
比较规则
比较两个字符的大小,容易想到的方法是比较两个字符对应的二进制数字大小,这个规则比较简单,但是不符合现实需求,比如’a’和’A’我们认为是相等的,这个时候就不适合使用这种方法了,可以先将字符全部转为大写或者小写,然后再比较。但是如果是中文字符呢?所以说,同一种字符集可以有多种不同的比较规则。
MySQL中的字符集
utf8字符集表示一个字符需要使用1-4个字节,但是我们常用的一些字符使用1-3个字节就可以表示了。MySQL中utf8实际上是被阉割过的字符集utf8mb3。utf8mb4才是正宗的utf8字符集。存储一些emoji表情之类的需要4个字节的,这个时候就只能使用utf8mb4字符集。
常用字符集(MaxLen表示该字符集一个字符最多需要几个字节)
| 字符集名称 | MaxLen |
|---|---|
| ascii | 1 |
| latin1 | 1 |
| gb2312 | 2 |
| gkb | 2 |
| utf8 | 3 |
| utf8mb4 | 4 |
MySQL中的比较规则
比较规则名称以与其关联的字符集的名称开头。比如utf8_general_ci、utf8_polish_ci。后边紧跟着该比较规则主要作用于哪种语言,utf8_polish_ci表示以波兰语的规则比较,utf8_general_ci表示通用的比较规则。
后缀意味着该比较规则是否区分语言中的重音、大小写啥的,具体可以用的值如下:
| 后缀 | 英文释义 | 描述 |
| ———- | —— |
| _ai | accent insensitive| 不区分重音|
| _as | accent sensitive| 区分重音|
| _ci | case insensitive | 不区分大小写 |
| _cs | case sensitive | 区分大小写|
| _bin | binary | 以二进制方式比较 |
MySQL中的字符集和比较规则级别
服务器级别
数据库级别
表级别,没有指定默认为数据库级别的字符集和比较规则
列级别,没有指定默认为表级别的字符集和比较规则
字符的编解码
从客户端发往服务器的请求本质上就是一个字符串,服务器向客户端返回的结果本质上也是一个字符串,而字符串其实是使用某种字符集编码的二进制数据。从发送请求到返回结果这个过程中伴随着多次字符集的转换,在这个过程中会用到3个系统变量。
| 系统变量 | 描述 |
|---|---|
| character_set_client | 服务器解码请求时使用的字符集 |
| character_set_connection | 服务器处理请求时会把请求字符串从character_set_client转为character_set_connection |
| character_set_results | 服务器向客户端返回数据时使用的字符集 |

服务器认为客户端发送过来的请求是用character_set_client编码的,假设你的客户端采用的字符集和 character_set_client 不一样的话,就会出现意想不到的结果。
服务器将把得到的结果集使用character_set_results编码后发送给客户端。假设你的客户端采用的字符集和 character_set_results 不一样的话,这就可能会出现客户端无法解码结果集的情况,结果就是在你的屏幕上出现乱码。
character_set_connection只是服务器在将请求的字节串从character_set_client转换为character_set_connection时使用,它是什么其实没多重要。
InnoDB存储结构
InnoDB是一个将表中的数据存储到磁盘上的存储引擎,所以即使关机后重启我们的数据还是存在的。
真正处理数据的过程是发生在内存中的,所以需要把磁盘中的数据加载到内存中,或者从内存中同步数据回磁盘中。这样如果数据是一条一条的读,效率是非常慢的,所以InnoDB采取的方式是将数据划分为若干页,以页作为磁盘和内存之间的基本单位,InnoDB中页的大小一般为16kb。
行格式
我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为行格式或者记录格式。目前为止行格式共有四种,分别是:Compact、Redundant、Dynamic和Compressed。
Compact行格式结构:

变长字段长度列表:
MySQL支持一些变长的数据类型,比如VARCHAR(M),TEXT类型等,使用这些字段存储多少字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节数也存起来。
NULL值列表:
某些列可能存在NULL值,如果把NULL值存在记录的真实地址,那么就比较浪费存储空间。所以直接把列值为NULL的记录统一存在NULL值列表。
NULL值列表必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节,则在字节的高位补0。一个字节8bit,如果列c1,c2,c3为NULL,那么应该是这样的:
| c3 | c2 | c1 | |||||
|---|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
记录头信息
记录当前的位置信息,还有一些预留位



