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

1次阅读

server层负责解析、优化和执行控制,不直接访问数据文件;存储引擎层(如innodb)负责读写.ibd文件、事务管理、加锁及索引维护,二者通过接口协作完成查询。

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

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 条件(除非用 BNLHash 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_issueSHOW ENGINE INNODB STATUS 交叉看。

text=ZqhQzanResources