《Mysql是怎样运行的》读书笔记一
开始第三刷
一、Mysql客户端和服务端连接
(1)通过tcp连接
真实环境中,数据库服务器进程和客户端进程可能运行在不同的主机中,它们之间必须通过网络来进行通讯。MySQL 采用 TCP 作为服务器和客户端之间的网络通信协议。(在网络中的其他进程就可以通过 IP地址 + 端口号 的方式来与这个数据库进程连接)
MySQL 服务器启动的时候会默认申请 3306 端口号,当然我们可以指定端口号比如下面的3307
mysql -h127.0.0.1 -uroot -P3307 -p //-p用于输入密码中间必须隔开 -P+端口号
(2)命名管道和共享内存:使用 共享内存 的方式进行通信的服务器进程和客户端进程必须在同一台 Windows 主机中。
(3) Unix域套接字文件:如果我们的服务器进程和客户端进程都运行在同一台操作系统为类 Unix 的机器上的话,我们可以使用 Unix域套接字文件 来进行进程间通信。
服务器处理客户端请求
不论客户端进程和服务器进程是采用哪种方式进行通信,最后实现的效果都是:**客户端进程向服务器进程发送一段文本(MySQL语句),服务器进程处理后再向客户端进程发送一段文本(处理结果)。**下图解释了服务器进程对客户端的请求做了什么处理。
-
连接管理:每当有一个客户端进程连接到服务器进程时,服务器进程都会创建一个线程来专门处理与这个客户端的交互,当该客户端退出时会与服务器断开连接,服务器并不会立即把与该客户端交互的线程销毁掉,而是将其缓存起来,在另一个新的客户端在进行连接时,把这个缓存的线程分配给新客户端。从而起到了减少频繁创建和销毁线程而导致性能下降的效果。
-
如果客户端程序和服务器程序不运行在一台计算机上,我们还可以采用使用了 SSL (安全套接字)的网络连接进行通信,来保证数据传输的安全性。
-
解析优化
- 查询缓存
Mysql服务器会把刚处理过的查询请求和结果 缓存起来,如果下次有一模一样的请求过来,直接从缓存查找结果。
此时有两个要求:
-
查询请求在任何字符上的不同(空格、注释、大小写),都会导致缓存不命中。
-
当缓存系统涉及到的每张表,表的结构改变(INSERT 、 UPDATE 、 DELETE 、 TRUNCATE TABLE 、 ALTER TABLE 、 DROP TABLE 或DROP DATABASE 语句,那使用该表的所有高速缓存查询都将变为无效并从高速缓存中删除!)
虽然查询缓存有时可以提升系统性能,但也不得不因维护这块缓存而造成一些开销,从MySQL 5.7.20
开始,不推荐使用查询缓存,并在MySQL 8.0中删除。
- 解析和优化
1、语法解析:因为客户端程序发送过来的请求只是一段文本而已,所以 MySQL 服务器程序首先要对这段文本做分析,判断请求的语法是否正确,然后从文本中将要查询的表、各种查询条件都提取出来放到 MySQL 服务器内部使用的一些数据结构上来。
2、查询优化:SQL 的优化程序会对我们的语句做一些优化,如外连接转换为内连接、表达式简化、子查询转为连接等一堆东西。优化的结果就是生成一个执行计划,这个执行计划表明了应该使用哪些索引进行查询,表之间的连接顺序是啥样的。我们可以使用EXPLAIN 语句来查看某个语句的执行计划
- 存储引擎
Mysql服务器将数据的存储和提取操作封装到一个叫 ‘存储引擎’ 的模块里, MySQL 提供了各式各样的 存储引擎 ,不同 存储引擎 管理的表具体的存储结构可能不同,采用的存取算法也可能不同。
二、InnoDB记录结构
Innodb页简介
Innodb 将数据划分为若干个页,以页作为磁盘和内存之间交互的基本单位,InnoDB页的大小一般为16KB。
为什么将页作为磁盘和内存的基本单位?
把磁盘中的数据加载到内存中,如果是处理写入或修改请求的话,还需要把内存中的内容刷新到磁盘上。如果Innodb一条条的把记录从磁盘读取,效率会很慢。况且业务操作的记录不止一条,往往都聚在一起,一页为单位也减少了一定的IO次数
Innodb行格式
-
目前为止Innodb有4种行格式:Compact、Redundant、Dynamic 和 Compressed 行格式
-
我们可以在创建或修改表的语句中指定 行格式 :
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMAT=行格式名称
接下来我们主要了解Compact行格式:
Compact行格式
- 变长字段长度列表:Mysql有一些变长的数据类型,比如VARCHAR(M) 、 VARBINARY(M) 、各种 TEXT 类型,各种 BLOB 类型,我们也可以把拥有这些数据类型的列称为 变长字段 ,变长字段中存储多少字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节数也存起来,这样才不至于把 MySQL 服务器搞懵,所以这些变长字段占用的存储空间分为两部分:
- 真正的数据内容
- 占用的字节数 (每个字符所占的字节 * 长度)
在compact行格式中,把所有变长字段的数据占用的字节长度都存放在记录的开头部分,形成一个变长字段长度列表,个变长字段数据占用的字节数按照列的顺序逆序存放
-
NULL值列表:把一行中某列为NULL存放在真实数据部分很占地方,所以Compact行格式把这些NULL的列统一管理,存储到NULL值列表中,统计过程如下
-
首先统计表中允许存储NULL的列有哪些
主键列或NOT NULL约束的列之外。
-
如果表中没有允许存储NULL的列,NULL值列表就不存在,否则将每个允许存储NULL的列对应一个二进制位,二进制位按照列的顺序逆序排列,二进制意义如下:
- 二进制位值为0,代表该列的值为NULL
- 二进制位值为1,代表该列的值不为NULL
-
-
记录头信息
名称 | 描述 |
---|---|
预留位 1、2 | 没用 |
delete_mask | 标记该记录是否被删除 |
min_rec_mask | B+树每层非叶子节点的最小记录都会添加该标记 |
n_owned | 表示当前记录拥有的记录数 |
heap_no | 表示当前记录在记录堆的位置信息 |
record_type | 表示当前记录的类型, 0 表示普通记录, 1 表示B+树非叶子节点记录, 2 表示最小记录, 3表示最大记录 |
next_record | 表示下一条记录的相对位置 |
真实的数据记录
除了记录非NULL列的值外,还有三个重要的列(也成为隐藏列)
即:DB_ROW_ID、DB_TRX_ID、DB_ROLL_PTR
- DB_ROW_ID(可选):
这里和Innodb表主键生成策略有关:
- 优先使用用户定义主键作为主键
- 如果用户没有定义主键,InnoDB 会为表默认添加一个名为row_id 的隐藏列作为主键。
-
DB_TRX_ID (事务id)
-
DB_ROLL_PTR (回滚指针)
先不提,很重要后面讲
所以一个Compact记录的格式为
对于CHAR(M)类型的列来说,当列采用定长字符集时,该列占用的字节数不会被加到变长字段长度列表,而如果采用变长字符集时,该列占用的字节数也会被加到变长字段长度列表
Redundant行格式(Mysql5.0之前)
对比Compact:
- 少了个NULL值列表