mysql Server层和存储引擎层如何协作_SQL执行分工解析

来源:这里教程网 时间:2026-02-28 20:50:59 作者:

MySQL 查询执行时,Server 层和存储引擎层各干啥?

Server 层不碰数据文件,只管解析、优化、执行控制;存储引擎层(如 InnoDB)才真正读写

.ibd
文件、管理事务、加锁、维护索引结构。一次
SELECT
执行,是 Server 层发指令、引擎层交结果的协作过程,不是“一起干活”。

一条 SELECT 语句的典型协作流程

SELECT * FROM users WHERE id = 123;
为例:

Server 层先调用
parser
做语法分析,生成解析树
再经
optimizer
生成执行计划:确认走
PRIMARY KEY
索引,决定用
index_read
接口
Server 层调用
handler::index_read()
(InnoDB 对应
ha_innobase::index_read()
),传入索引键值
123
InnoDB 在内存或磁盘定位 B+ 树叶子页,读出整行数据,按 Server 层要求的格式(
TABLE::record[0]
内存布局)填充后返回
Server 层收到后做字段过滤(如
WHERE name LIKE '%a%'
)、聚合、排序等——这些若无法下推到引擎层,就得自己处理

哪些操作能下推?哪些必须 Server 层兜底?

下推能力取决于存储引擎接口支持程度。InnoDB 支持部分条件下推,但远不如 MyISAM 或列存引擎(如 ClickHouse)激进:

能下推的:主键/唯一索引等值查询、索引范围扫描(
WHERE created_at BETWEEN ? AND ?
)、
ORDER BY indexed_col
(且无额外计算)
不能下推的:含函数的条件(
WHERE YEAR(created_at) = 2023
)、多表 JOIN 条件(除非用
BNL
Hash Join
且引擎支持)、
GROUP BY
聚合(InnoDB 不返回分组结果,Server 层自己 hash/group)
特别注意:即使走了索引,
SELECT *
仍需 InnoDB 回表读聚簇索引完整行;而
SELECT id
若覆盖索引可用,则无需回表——这个判断和执行由 Server 层做出,但是否真能避免回表,取决于引擎是否提供
covering index
信息

常见协作失配导致的性能问题

很多慢查不是 SQL 写得差,而是 Server 和引擎之间“沟通低效”:

Server 层误判执行计划(比如统计信息过期),让引擎做全表扫描,而实际只需查 3 行——用
ANALYZE TABLE
更新统计信息可缓解
引擎返回大量数据(如没加
LIMIT
的宽表扫描),Server 层还得逐行拷贝、转换字符集、检查权限——这时
handler::rnd_next()
调用次数爆炸,
Created_tmp_tables
上升
InnoDB 的
row_search_mvcc()
在 RC 隔离级下需构造多个版本,但 Server 层只说“给我这行”,不告诉“我要哪个一致性视图”——视图由 Server 层在事务开启时创建并透传给引擎,漏传或复用错误会导致幻读或不可重复读
mysql> SHOW PROFILE FOR QUERY 1;
+----------------------+----------+
| Status               | Duration |
+----------------------+----------+
| starting             | 0.000056 |
| checking permissions | 0.000012 |
| Opening tables       | 0.000028 |
| init                 | 0.000021 |
| System lock          | 0.000014 |
| optimizing           | 0.000029 |
| statistics           | 0.000087 |
| preparing            | 0.000023 |
| executing            | 0.000005 |
| Sending data         | 0.021341 | <-- 这里耗时高,说明引擎返回慢或 Server 处理慢
| end                  | 0.000011 |
+----------------------+----------+

真正难调的是“Sending data”阶段——它既可能卡在 InnoDB 的 buffer pool 争抢,也可能卡在 Server 层的字符串转码或大对象复制。得结合

perf record -e block:block_rq_issue
SHOW ENGINE INNODB STATUS
交叉看。

相关推荐