开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第01天,点击查看活动详情
MySQL 是典型的 C/S 结构,服务端程序是 mysqld,客户端程序是 mysql。
服务端进程包括两部分内容:
- server 层,主要包括连接器、查询缓存、解析器(词法、语法分析)、优化器和执行器,负责建立、管理连接,分析和执行 SQL 语句。
- engine 层,主要包括各种存储引擎实现,例如 InnoDB、MyISAM、Memory 等多个实现,负责数据的存储和读取。
接下来,我们将按照上述分层来逐步了解和学习 MySQL 服务端程序。
01-服务层
01.1-连接器
故名思议,连接器负责 MySQL 客户端进程与服务端进程之间的连接管理工作。 客户端与服务端之间的连接基于 TCP 协议。
通过如下命令,我们便可以 user_name 的身份登录 host 主机上的 MySQL 服务。
mysql -h${host} -u${user_name} -p
当用户名、密码验证通过后,Server 会从权限表中查询用户的权限,并且后续的权限判断都基于此时查询到的结果。 所以,如果对用户权限进行修改,并不会影响已建立的连接,只会影响该用户后续的连接。
如何查看当前有哪些用户与服务端建立了连接呢?可以通过如下命令:
--- mysql> show processlist;
+----+--------+-----------+------------+---------+------+-------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+--------+-----------+------------+---------+------+-------+------------------+
| 14 | samson | localhost | SAMSONS_DB | Query | 0 | init | show processlist |
| 15 | samson | localhost | SAMSONS_DB | Sleep | 300 | init | NULL |
+----+--------+-----------+------------+---------+------+-------+------------------+
当 Command 列为 Sleep 时,说明连接完成后未执行其他命令,连接为空闲连接,且空闲时长为 300s。
MySQL 会在连接空闲一定时间后断开连接,空闲时间配置可以通过 show variables like 'wait_timeout'; 查看,默认的空闲时间为8小时,即28800s。
也可通过命令手动断开连接,例如:
--- 断开 id=15 的空闲连接
kill connection +15;
如何查看支持的最大连接数呢?可以通过 show variables like 'max_connections'; 查看,默认值为151。
因为客户端与服务段之间通过 TCP 连接,所以这个值也会受到所在服务器的限制。
而且,MySQL 连接也跟 HTTP 连接一样,有所谓的短连接、长连接,前者指每条 SQL 都需要经历 TCP 的三次握手和四次挥手,后者指一次连接之间会执行多条 SQL。 两者各有利弊:
- 对短连接来说,每次 SQL 都需要重新建立连接,会使执行效率较低,好处就是服务端不需要持续维护连接,节省服务器资源;
- 对长连接来说,省去了每次都要建立连接的代价,效率会较高,但是呢服务器端需要维护连接,当连接过多时会导致 OOM 而重启。
在现代应用开发过程中,为了提高访问数据库的效率,一般都会使用数据库连接池来充分利用长连接带来的优势。 为了避免长连接占用资源的弊端,一般采用:
- 定期断开长连接。
- 主动重置长连接,恢复到连接刚建立时的状态。
01.2-查询缓存
用来缓存查询语句的结果,以查询语句作为 key,以语句对应的结果作为 value,若命中缓存则直接返回缓存的结果。 对于只读数据库、或者读多写少的数据库,作用比较大; 但对那些需要经常更新的数据库来说,此功能比较鸡肋。
在 MySQL 8.0版本中,此功能被删除了,所以不再深究此功能。
01.3-解析器
解析器负责解析客户端传来的 SQL 语句或其他命令。 首先,词法分析将客户端命令解析成语法树,识别出要执行的方法、表名、列名等,方便后续的语法分析; 然后,语法分析将判断前一步的语法树是否满足 SQL 语法,并在不满足时向客户端返回对应的错误。
01.4-执行 SQL
经过前面的步骤以后,接下来就是 SQL 的执行阶段。 一般来说,执行可以分为三个阶段1:
- 预处理阶段,负责检查表或字段(列)是否存在、将
select *语句中的*替换为所有列名等工作。 - 优化阶段,优化器根据一系列的策略选择索引等执行计划,可以通过
explain来查看 SQL 语句的执行计划。 - 执行阶段,将执行计划提交到存储引擎中,并等待结果返回。
02-存储引擎层
MySQL 支持 InnoDB、MyISAM、Memory 等多个存储引擎,不同存储引擎之间共享一个 Server 层。
如何指定不同的数据存储引擎?在创建表格时可以通过 engine 关键字指定要使用的数据存储引擎,例如:
CREATE TABLE hero (
number INT,
name VARCHAR(100),
country varchar(100),
PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8;
自 MySQL 8.0开始,InnoDB 是默认的存储引擎。 InnoDB 中,以 B+ 树形式存储索引,包括聚簇索引(主键索引)、二级索引。
02.1-字符集
MySQL 中支持多种字符集,例如常见的 utf8、GBK、ASCII 等。
utf8 字符集中,每个字符需要1~4个字节表示; GBK 字符集中,每个字符需要1-2个字节表示; ASCII 字符集中,每个字符只需要1个字节表示。
02.2-行记录
每个存储引擎实现的行记录格式都不相同,InnoDB 作为最常用的存储引擎,它支持4种不同格式的行记录格式:
- compact
- redundant
- dynamic
- compressed
如何制定使用哪一种行格式呢?可以用 ROW_FORMAT=COMPACT 关键字指定,例如:
CREATE TABLE hero (
number INT,
name VARCHAR(100),
country varchar(100),
PRIMARY KEY (number)
) Engine=InnoDB CHARSET=utf8 ROW_FORMAT = COMPACT ;
--- 或修改已有表格
ALTER TABLE hero ROW_FORMAT = COMPRESSED ;
行记录是理解数据引擎存储数据的重要内容之一,后面会专门的学习格式内容
02.3-数据组织方式
在 InnoDB 中,数据行以页(page)的方式组织,且内存、磁盘之间也是以页为单位传输。 页的大小为16KB。 InnoDB 中,存储数据、索引的页被称为索引页或数据页。 64 个连续页称为区(extent),大小为1MB。 256个区称为一组(group)。
02.4-索引
InnoDB 中,数据是以主键为索引的 B+ 树形式存储的,也被称为聚簇索引。 在聚簇索引形成的 B+ 树中,所有的叶子节点存储的是实际的数据,所有非叶子节点存储的是冗余的索引。
除了聚簇索引(主键),为其他列定义的索引也被称为二级索引。 根据二级索引查询主键,然后根据查询到的主键在聚簇索引中查询主键对应的行记录的过程,称为回表。
03-总结
在今天的文章中,我们从全局的角度大致了解了 MySQL 服务端程序的层次结构,主要包括服务器层、存储引擎层。 接下了我们学习了每层主要的模块及它们负责的功能。 在今后的多篇文章中我们会进一步学习各个模块的详细内容,如果对 MySQL 内容感兴趣的话,希望关注后续的文章。