mysql
mysql
一条sql经历了什么
主要分为 Server 层(负责逻辑)和 存储引擎层(负责物理读写)
第一阶段:连接管理 (Connection Handling)
当客户端(如 Go 程序、Navicat)发起请求时,服务端首先由连接器接待。
- 三次握手:建立 TCP 连接。
- 身份验证:校验用户名和密码。
- 权限读取:验证通过后,连接器会到权限表中查询该用户拥有的权限,并保存在当前连接的上下文中。
- 注意: 只要连接不断开,即使管理员中途修改了权限,当前连接也感知不到,必须重新连接。
第二阶段:解析与预处理 (Parser & Preprocessor)
连接建立后,SQL 进入“语法分析”阶段。
- 词法分析 (Lexical Analysis):MySQL 会识别出 SQL 里的关键字。比如
SELECT识别为查询,FROM后面是表名,WHERE后面是过滤条件。 - 语法分析 (Syntax Analysis):根据 SQL 语法规则,判断你写的 SQL 是否合规(比如有没有少个逗号)。如果没问题,会生成一棵 解析树 (Parse Tree)。
- 预处理器 (Preprocessor):
- 检查表名或字段名是否存在。
- 检查是否有对应字段的查询权限。
- 将别名还原等。
第三阶段:查询优化 (Optimizer)
这是 MySQL 最核心的“大脑”部分。
- 执行计划制定:优化器会根据成本 (Cost) 模型,决定:
- 如果有多个索引,用哪个索引?
- 多表关联时,先驱动哪张表(连接顺序)?
- 重写 SQL:将复杂的逻辑简化,或者进行“谓词下推”等优化。
- 最终产物:生成一个执行计划。你可以通过
EXPLAIN命令看到这个计划。
第四阶段:执行器 (Executor)
拿到执行计划后,真正的“搬砖”工作开始了。
- 权限校验:开始执行前再次校验是否对该表有执行具体操作的权限(虽然预处理查过,但执行器是最终把关人)。
- 调用存储引擎接口:执行器并不直接读文件,它通过标准的 API 接口去问存储引擎(如 InnoDB)拿数据。
- 例子:执行器问:“给我
users表第一行。” - InnoDB 答:“给,这是数据。”
- 执行器问:“这行
id是 1 吗?如果是,我就存到结果集;如果不是,跳过。再给我下一行。”
- 例子:执行器问:“给我
第五阶段:存储引擎层 (Storage Engine)
这是真正和磁盘打交道的地方(以 InnoDB 为例)。
- Buffer Pool:首先看内存(Buffer Pool)里有没有数据,有则直接返回。
- 磁盘 IO:内存没有,则从磁盘加载数据页。
- 返回数据:将结果返回给执行器。
特别注意:查询缓存 (Query Cache) 如果你看的是旧教材,可能会提到“查询缓存”。
MySQL 8.0 已经彻底删除了查询缓存功能。因为它失效太快(只要表有更新,缓存全灭),在现代高并发场景下弊大于利。
MySQL 死锁检测算法 & 选择主动牺牲的事务
MySQL 解决死锁的核心是 基于等待图(Wait-for Graph, WFG)的死锁检测算法,而选择主动牺牲(回滚)的事务遵循 最小回滚代价原则,整个流程由 InnoDB 引擎自动完成,无需人工干预。
一、死锁检测核心算法:等待图(WFG)检测
InnoDB 是基于行锁实现事务并发控制的,死锁的本质是多个事务间形成了循环等待锁资源的闭环。其检测流程如下: