Mysql高频八股——SQL语句的执行过程
大家好,我是钢板兽!
今天这篇文章本来想把SQL语句的执行过程和事务与undo log、redo log的联系放在一起写的。SQL语句的执行过程中会涉及到undo log、redo log,而undo log、redo log更深入的原理也是面试中经常会问到的,所以把它们放在一起再合适不过了,但是写着写着发现内容太多,于是拆成了两篇。
这篇文章会带你理解SQL语句的执行过程,在探究SQL语句的执行过程前,我们要先知道MySQL的基础架构。
1.MySQL的基础架构
MySQL的架构主要分为两大核心部分:Server层和存储引擎层。
(1)Server层:主要包括连接器、查询缓存、分析器、优化器、优化器,还有一个通用的日志模块 binlog 日志模块。
- 连接器:接受客户端请求,验证账号密码,确定身份权限。如果通过身份验证,就能连接数据库了。
- 查询缓存:存储之前执行过的查询结果。如果有和之前执行的SQL完全相同的缓存记录,就直接返回。(MySQL 8.0 版本后移除)
- 分析器:负责语法分析(语句写法对不对)和词法分析(引用的表和字段是否存在)。
- 优化器:生成高效的执行计划,选择最优的索引和执行方式。
- 执行器:执行具体的数据操作,调用存储引擎完成数据读取或修改,并将结果返回给连接器。
(2)存储引擎层:负责数据的物理存储和读取,采用可替换的插件式架构,我们甚至可以为不同的数据库表设置不同的存储引擎以适应不同场景的需要。存储引擎是基于表的,而不是数据库。
MySQL支持 InnoDB、MyISAM、Memory 等多个存储引擎,其中 InnoDB 引擎有自有的日志模块 redolog 模块,在MySQL5.5之后默认使用InnoDB作为存储引擎。
Server层和存储引擎层通过存储引擎接口交互,允许不同存储引擎实现自定义的数据管理策略,提高MySQL整体架构的灵活性。
2.SQL语句的执行过程
当SQL语句被提交到MySQL后,一般会经过这几个阶段:连接器 → 查询缓存 → 分析器 → 优化器 → 执行器 → 存储引擎。
具体过程其实就是上一节MySQL基础架构的内容,这里通过举例子给出查询语句和更新语句的执行细节。
比如我们现在有两张表:
- 学生表(
students
):
student_id | name | class |
---|---|---|
1 | Winnie | 文学101 |
2 | Dan | 文学102 |
3 | Jane | 文学101 |
- 成绩表(
scores
):
id | student_id | subject | score |
---|---|---|---|
1 | 1 | English | 93 |
2 | 1 | Math | 95 |
3 | 2 | English | 88 |
4 | 3 | Math | 91 |
2.1 查询语句
查询文学101班级中英语科目成绩大于90分的学生姓名及成绩:
SELECT s.name, sc.score
FROM students s
JOIN scores sc ON s.student_id = sc.student_id
WHERE s.class = '文学101' AND sc.subject = 'English' AND sc.score > 90;
执行过程:
-
连接器:验证用户权限和数据库访问权限。
-
查询缓存:通常新版本MySQL默认关闭缓存,这里假设未使用缓存。
-
分析器:检查语法是否正确;验证表名和字段名是否存在:
students
表存在,字段存在。scores
表存在,字段存在。 -
优化器:优化器会分析多个执行路径,以下为两种可行的执行计划:
- 计划一:全表扫描(Full Table Scan):假设数据库未建立索引,优化器会选择全表扫描:首先在
students
中扫描所有记录,找到class = '文学101'
的记录。再到scores
表匹配每一条满足条件的学生记录,逐条检查科目为English
且成绩大于90的记录。 - 计划二:索引扫描(Index Scan):假设数据库对关键字段建立了索引,比如:
students.class
字段建立了索引。scores.subject
和scores.score
字段建立了联合索引。
此时优化器会选择用索引扫描:
- 先快速定位到
students
中class = '文学101'
的所有学生(快速索引扫描)。 - 再快速定位
scores
表中满足subject='English'
并且score>90
的数据记录(通过联合索引快速定位)。 - 通过索引快速完成匹配,取出最终结果。
- 计划一:全表扫描(Full Table Scan):假设数据库未建立索引,优化器会选择全表扫描:首先在
- 执行器:根据优化器选定的计划去调用存储引擎获取数据:使用索引快速定位数据页。存储引擎:**
- 存储引擎:从物理存储位置取出实际数据,返回给执行器。
2.2 更新语句
给文学101班英语科目的所有学生的成绩提高2分:
UPDATE scores sc
JOIN students s ON sc.student_id = s.student_id
SET sc.score = sc.score + 2
WHERE s.class = '文学101' AND sc.subject = 'English';
更新语句基本上和上面的查询语句流程一样,但是执行更新操作的时候要记录日志,MySQL 自带的日志模块是 binlog(归档日志),所有的存储引擎都可以使用,常用的 InnoDB 引擎自带一个日志模块 redo log(重做日志),这里以 InnoDB 引擎来探讨更新语句的执行流程。执行过程如下:
-
连接器:验证用户权限和数据库访问权限。
-
查询缓存:不会走查询缓存,因为更新语句会导致与该表相关的查询缓存失效。(同样的,删除、增加数据也不会走查询缓存)
-
分析器:确认语法、表名、字段名无误。
-
优化器:若建立索引,快速定位满足
class='文学101'
和subject='English'
的数据。若无索引,只能进行全表扫描。 -
执行器和日志记录(重点):执行器调用存储引擎更新数据后,会执行日志机制:
- 存储引擎将数据修改记录在redo log缓冲区中。
- 执行完成事务提交,写入redo log磁盘文件和binlog磁盘文件。
- redo log用于数据完成持久化,保证数据库崩溃恢复能力。binlog确保主从同步和数据库复制的数据一致性。
更深入的细节在第四节探究。
总结一下,SQL语句执行过程可概括为:
- 查询语句:
连接 → (缓存) → 分析 → 优化 → 执行 → 存储引擎
- 更新/增加/删除语句:
连接 → 分析 → 优化 → 执行(redo log记录) → binlog记录 → 存储引擎更新
如果你觉得这篇文章对你有帮助,欢迎点赞、转发、留言!