目录
正在加载目录…
专栏文章
专栏文章
MySQL 系列
1. MySQL:核心概念、架构与使用场景 2. MySQL 数据类型与 Java 类型映射 3. MySQL 基础架构与执行流程 4. MySQL InnoDB 日志系统 5. MySQL 事务与 MVCC 6. MySQL 索引原理与优化 7. MySQL 锁机制 8. MySQL 性能问题排查 9. MySQL 主备复制与高可用 10. MySQL 实战技巧与常见陷阱 11. MySQL 数据库设计规范 12. MySQL SQL 函数与查询技巧 13. MySQL InnoDB Buffer Pool 原理 14. MySQL 排序与聚合原理

MySQL 基础架构与执行流程

发布于 2026-05-26 10:33 · 最后编辑于 2026-07-31 15:52 · 字数 1,444 👁 93 次阅读

一条 SQL 从发出到返回结果,经历了哪些组件、做了什么?本文以 Server 层 + 存储引擎层为主线,拆解 MySQL 逻辑架构及查询/更新语句的完整执行路径。

目录

章节说明
整体架构Server 层与存储引擎层的分工
查询语句执行流程连接器→分析器→优化器→执行器
更新语句执行流程多了 redo log 和 binlog 的写入
连接管理长连接的内存问题与应对方案
查询缓存为什么不建议使用

整体架构

mysql arch

关键设计:不同存储引擎共用同一个 Server 层,存储引擎以插件形式接入。

层级职责
Server 层SQL 解析、权限校验、查询优化、内置函数
存储引擎层数据存储和读取,不同引擎能力不同

查询语句执行流程

SELECT * FROM T WHERE ID=10 为例:

flowchart TD
    A["客户端发送查询"] --> B["连接器<br/>建立连接、认证身份、获取权限"]
    B --> C{"查询缓存<br/>是否命中?"}
    C -->|命中| D["直接返回结果(8.0 已删除)"]
    C -->|未命中| E["分析器<br/>词法分析 + 语法分析"]
    E --> F["优化器<br/>选择索引、确定 join 顺序"]
    F --> G["执行器<br/>调用存储引擎接口逐行读取"]
    G --> H["返回结果集"]
    style D fill:#fcc,stroke:#c00

各组件职责

组件职责典型错误
连接器TCP 握手、用户名/密码认证、读取权限Access denied for user
分析器词法分析(识别关键字/表名/列名)+ 语法分析You have an error in your SQL syntax
优化器选择使用哪个索引、决定多表 join 顺序选错索引(可用 force index 干预)
执行器验证表级权限,调用引擎接口逐行读取SELECT command denied to user

权限校验的三层机制

为什么不在分析器阶段做权限校验?

SQL 确实先经过连接器,但连接器是透传层——只管理网络连接,收到 SQL 后原样转发给分析器,不解读 SQL 内容(职责分离)。即使连接器"看"了 SQL,仍然无法做细粒度权限校验,因为:

  • 视图SELECT * FROM order_view 要知道权限,需先展开视图得到底层表,发生在优化器阶段
  • 存储过程:内部访问哪些对象,执行前不知道
  • 列级权限SELECT * 展开后的具体列,需查元数据后才能校验

三层权限校验完整链路:

① 连接建立时(连接器)
   ├─ 身份认证:用户名 + 密码
   └─ 读取并缓存全局权限(mysql.user)→ 后续所有请求复用此缓存

② SQL 到来,执行器阶段
   ├─ 库级权限:有没有权限访问此 database(mysql.db)
   ├─ 表级权限:有没有权限操作此 table(mysql.tables_priv)
   ├─ 列级权限:有没有权限访问这些列(mysql.columns_priv)
   └─ 视图/存储过程展开后的底层对象权限

⚠️ 重要:执行器用的是连接建立时缓存的权限快照,而非实时查权限表。因此 GRANT 改权限后旧连接不会立即生效,需断开重连(或 FLUSH PRIVILEGES)。

语法错误(分析器)和权限错误(执行器)是不同阶段的不同报错来源:You have an error in your SQL syntax vs SELECT command denied to user

rows_examined 与实际扫描行数

慢查询日志中 rows_examined 表示执行器调用引擎接口的次数,不等于引擎内部实际扫描的行数(引擎一次调用可能内部扫了多行)。

更新语句执行流程

更新语句(UPDATE/INSERT/DELETE)走同样的 Server 层流程,额外多了两个日志模块

执行器读取 ID=2 的行(通过 InnoDB 接口)
    ↓
执行器计算新值,调用 InnoDB 写入接口
    ↓
InnoDB 将操作写入 redo log(prepare 状态)
    ↓
执行器写入 binlog 到磁盘
    ↓
InnoDB 提交 redo log(commit 状态)

两阶段提交(2PC) 是为了保证 redo log 和 binlog 的一致性,详见日志系统笔记。

连接管理

长连接 vs 短连接

对比长连接短连接
定义请求持续复用同一连接每次查询后断开
开销建连少,但内存累积频繁建连,开销大
推荐✅ 推荐(减少建连开销)❌ 不推荐

长连接内存累积问题

MySQL 在执行过程中的临时内存挂在连接对象上,连接断开时才释放。长连接积累下来,可能导致 OOM,现象为 MySQL 异常重启。

两种解决方案

-- 方案1:定期断开长连接(执行大查询后主动断开)
-- 代码层主动关闭连接

-- 方案2(推荐):MySQL 5.7+ 定期重置连接资源
-- 不需要重连,不需要重新认证
mysql_reset_connection()

连接超时参数

-- 查看空闲连接超时时间(默认 8 小时)
SHOW VARIABLES LIKE 'wait_timeout';

-- 查看当前所有连接(Sleep 状态为空闲连接)
SHOW PROCESSLIST;

查询缓存

为什么不建议使用

  • 失效极频繁:任何对表的更新都会清空该表所有查询缓存
  • 更新频繁的表,命中率接近 0,缓存维护成本远大于收益
  • MySQL 8.0 已完全删除查询缓存功能

适合使用查询缓存的唯一场景

几乎不更新的静态配置表(如系统参数表),可用 SQL_CACHE 显式指定:

-- 仅在 8.0 以下版本有效
SELECT SQL_CACHE * FROM system_config WHERE id = 1;

参考资料

← 返回列表

评论 (0)

暂无评论,来留下第一条吧。
登录注册 后才能发表评论