MySQL是怎样运行的——读书笔记
更新: 7/16/2025 字数: 0 字 时长: 0 分钟
字符集
MySQL中的utf8指的是utf8mb3这个字符集只用到了3个字节,若要使用使用完整的字符集需要使用utf8mb4
比较规则
utf8_general_ci
我们来看这个比较规则,它分为三部分
- utf-8:该规则用于哪个字符集
- general:主要根据哪个语种的特点进行排序,这里的general是一种相对通用的规则
- ci:是否区分重音和大小写
后缀 | 英文释义 | 描述 |
---|---|---|
_ai | accent insensitive | 不区分重音 |
_as | accent sensitive | 区分重音 |
_ci | case insensitive | 不区分大小写 |
_cs | case sensitive | 区分大小写 |
_bin | binary | 以二进制方式比较 |
特别注意的是,每种字符集都有自己默认的比较规则utf8
字符集默认的比较规则就是utf8_general_ci
。
MySQL的编解码顺序
首先客户端会有一个自己使用的字符集(一般与操作系统一致,Windows使用GBK,类Unix使用utf8),而在接收到客户端发送的字节并将查询到的数据返回给客户端时会用到3个字符集
系统变量 | 描述 |
---|---|
character_set_client | 服务器解码请求时使用的字符集 |
character_set_connection | 服务器处理请求时会把请求字符串从character_set_client 转为character_set_connection |
character_set_results | 服务器向客户端返回数据时使用的字符集 |
- 客户端会以自己的字符集形式发送一段字节给服务端
- 服务端收到后将客户端的数据认为为
character_set_client
类型,然后转换为character_set_connection
用于操作 - 服务端将查询到的数据将其由其自身的字符集转换为
character_set_results
,然后再返回给客户端 - 客户端接收到服务端返回的数据,再以自身字符集进行解码
InnoDB
在InnoDB中,我们的数据都是存放在磁盘上,然后在内存中进行操作,而一条条的由内存向磁盘中存取数据太慢,因此InnoDB采用页存储的方式,规定一页为16kb,一次存取的大小最少都是16k,即使你只查询一条数据,InnoDB 最少也会读取16KB的数据到内存中
varchar溢出
众所周知,varchar(M)最多可以存放65535个字节长度的数据,但是实际上M的值并非65535/每个字符的大小,这是因为varchar会使用一些字节来保存信息。
隐藏主键
在MySQL中你可以指定主键,但是如果你不指定主键,那么MySQL就会自动的选取一个unique的键作为主键。
那么如果表中甚至没有unique的字段呢?那么MySQL会生成一个名为row_id
的键作为主键,这个键我们看不到,但他确实存在于我们的数据库中,充当主键的作用。
页
InnoDB中管理的基本单位为页,其中存放数据的页被称之为索引Index
页
一个索引页中的大致分为下列7个部分
名称 | 中文名 | 占用空间大小 | 简单描述 |
---|---|---|---|
File Header | 文件头部 | 38 字节 | 页的一些通用信息 |
Page Header | 页面头部 | 56 字节 | 数据页专有的一些信息 |
Infimum + Supremum | 最小记录和最大记录 | 26 字节 | 两个虚拟的行记录 |
User Records | 用户记录 | 不确定 | 实际存储的行记录内容 |
Free Space | 空闲空间 | 不确定 | 页中尚未使用的空间 |
Page Directory | 页面目录 | 不确定 | 页中的某些记录的相对位置 |
File Trailer | 文件尾部 | 8 字节 | 校验页是否完整 |
当你存储数据时实际上是先充FreeSpace中申请一个空间,然后将数据存放进去,其转变为UserRecords
索引
InnoDB中的索引是通过B+Tree的形式建立的,大致是以索引键->页(目录项)
的形式进行存储,这种结构和正常的记录类似,因此InnoDB是复用了原本记录数据的数据页来存储目录项一条目录项记录只存储索引键以及其对应的页号,然后为了方便的找出目录项记录所在的页,会向上再次建立一个更高级的目录,这也就是索引B+Tree的构建方式。
对于聚簇索引(主键索引),其叶子节点会是完整的用户记录,也就是包含了用户所有数据的列。而二级索引(非聚簇索引),其叶子节点则是索引键->主键
,然后再通过聚簇索引来寻找到真正的用户记录,我们称呼这种操作叫回表
对于联合索引(这里用c1,c2,c3举例),它实际上是使用一棵B+Tree,然后通过[c1的值, c2的值, c3的值, 主键的值]
的形式创建的c1相同通过c2排序,c2相同通过c3排序,这样也能解释为什么会存在最左匹配原则(也就是c1 c3
,c1 c2
可以触发索引,c2 c3
c2 c1
无法触发索引)
全值搜索
值得注意的是MySQL中存在优化器,即使你的查询条件是 b = 2 and a = 1
,如果建立的是 (a, b)
联合索引,优化器会自动将其转换为 a = 1 and b = 2
,从而可以使用索引。
匹配列前缀
对于like(模糊匹配),因为是通过字符串的排序形式,所以只用前缀固定的情况才可以触发索引
匹配范围值
SELECT * FROM person_info WHERE name > 'Asa' AND name < 'Barlow' AND birthday > '1980-01-01';
对于这样的一个索引,其实使用不到birthday的索引的,因为name的值是不固定的,而我们的联合索引只有name相同的时候才会对birthday进行排序
SELECT * FROM person_info WHERE name = 'Ashburn' AND birthday = '1980-01-01' AND phone_number > '15100000000';
如果是上面这种就可以了,因为前方的已经固定了