Skip to content

MySQL是怎样运行的——读书笔记

更新: 7/16/2025 字数: 0 字 时长: 0 分钟

字符集

MySQL中的utf8指的是utf8mb3这个字符集只用到了3个字节,若要使用使用完整的字符集需要使用utf8mb4

比较规则

utf8_general_ci我们来看这个比较规则,它分为三部分

  • utf-8:该规则用于哪个字符集
  • general:主要根据哪个语种的特点进行排序,这里的general是一种相对通用的规则
  • ci:是否区分重音和大小写
后缀英文释义描述
_aiaccent insensitive不区分重音
_asaccent sensitive区分重音
_cicase insensitive不区分大小写
_cscase sensitive区分大小写
_binbinary以二进制方式比较

特别注意的是,每种字符集都有自己默认的比较规则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服务器向客户端返回数据时使用的字符集
  1. 客户端会以自己的字符集形式发送一段字节给服务端
  2. 服务端收到后将客户端的数据认为为character_set_client类型,然后转换为character_set_connection用于操作
  3. 服务端将查询到的数据将其由其自身的字符集转换为character_set_results,然后再返回给客户端
  4. 客户端接收到服务端返回的数据,再以自身字符集进行解码

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 c3c1 c2可以触发索引,c2 c3 c2 c1无法触发索引)

全值搜索

值得注意的是MySQL中存在优化器,即使你的查询条件是 b = 2 and a = 1,如果建立的是 (a, b) 联合索引,优化器会自动将其转换为 a = 1 and b = 2,从而可以使用索引。

匹配列前缀

对于like(模糊匹配),因为是通过字符串的排序形式,所以只用前缀固定的情况才可以触发索引

匹配范围值

sql
SELECT * FROM person_info WHERE name > 'Asa' AND name < 'Barlow' AND birthday > '1980-01-01';

对于这样的一个索引,其实使用不到birthday的索引的,因为name的值是不固定的,而我们的联合索引只有name相同的时候才会对birthday进行排序

sql
SELECT * FROM person_info WHERE name = 'Ashburn' AND birthday = '1980-01-01' AND phone_number > '15100000000';

如果是上面这种就可以了,因为前方的已经固定了

本站访客数 人次      本站总访问量