一条 SQL 语句的内部执行流程详解(MySQL为例)_mysql一条sql查询语句的执行流程
当执行如下 SQL:
SELECT * FROM users WHERE id = 1;
在数据库内部,其实会经历多个复杂且有序的阶段。以下是 MySQL(InnoDB 引擎)中 SQL 查询语句从发送到结果返回的完整执行流程。
客户端连接阶段
- 客户端(如 JDBC、MySQL Shell)通过 TCP 与 MySQL 服务器建立连接。
- 连接器模块完成身份认证(用户名/密码)、权限校验。
- 若使用连接池,连接可能已被复用。
语法分析阶段(Parser)
1. 词法分析(Lexical Analysis)
- 将 SQL 字符串拆解成关键字、标识符、操作符等 Token。
- 例子:
SELECT
,*
,FROM
,users
,WHERE
,id
,=
,1
2. 语法分析(Syntax Analysis)
- 依据 SQL 语法规则生成抽象语法树(AST)。
- 若语法不合法,此阶段抛出语法错误。
预处理阶段(Preprocessor)
- 验证表/字段是否存在。
- 检查当前用户是否有访问权限。
- 解析字段别名、函数等表达式。
- 确定查询涉及的表和列。
- 最终输出逻辑查询结构。
查询优化阶段(Optimizer)
优化器根据预处理阶段的语义结构生成最优执行计划(Execution Plan)。
1. 访问路径选择
- 使用 索引扫描 还是 全表扫描?
- 是否走覆盖索引,是否需要回表?
2. 连接顺序优化(Join Order)
- 对多表 JOIN,决定访问顺序与连接方法(如 Nested Loop、Hash Join)。
3. 成本估算(Cost Estimation)
- 评估每种执行方式的代价(IO 次数、内存使用等)。
- 选择代价最小的执行路径。
查询执行阶段(Executor)
执行器根据优化器生成的执行计划与存储引擎交互,完成数据访问。
执行器主要职责:
- 调用引擎接口访问表和索引。
- 进行 WHERE 过滤、JOIN、聚合、排序、分组等操作。
- 构造并返回最终结果集。
存储引擎访问阶段(以 InnoDB 为例)
MySQL 使用插件式存储引擎架构。以 InnoDB 为例:
- 数据页首先尝试从 Buffer Pool(缓冲池)中读取。
- 若不在缓冲池,则从磁盘读取并加入缓冲池。
- 使用 B+ 树索引定位记录。
- 如果为覆盖索引(索引包含查询列),可避免回表。
- 对于非索引字段,需根据主键“回表”查找。
结果返回阶段
- 执行器生成的结果集通过 MySQL 协议格式化。
- 数据从服务器通过网络传输返回给客户端。
- 客户端解析并展示结果。
日志与事务支持(InnoDB)
虽然 SELECT 查询本身不会写入日志,但其他 SQL 会涉及以下机制:
- Undo Log:支持事务回滚、MVCC。
- Redo Log:保证事务持久化(WAL机制)。
- Binlog:记录变更操作,用于主从复制和恢复。
注:查询语句可能间接使用 undo log(如 MVCC)。
SQL 执行流程图
#mermaid-svg-OIZ1kthaw3BZkbFO {font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO .error-icon{fill:#552222;}#mermaid-svg-OIZ1kthaw3BZkbFO .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-OIZ1kthaw3BZkbFO .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-OIZ1kthaw3BZkbFO .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-OIZ1kthaw3BZkbFO .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-OIZ1kthaw3BZkbFO .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-OIZ1kthaw3BZkbFO .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-OIZ1kthaw3BZkbFO .marker{fill:#333333;stroke:#333333;}#mermaid-svg-OIZ1kthaw3BZkbFO .marker.cross{stroke:#333333;}#mermaid-svg-OIZ1kthaw3BZkbFO svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-OIZ1kthaw3BZkbFO .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OIZ1kthaw3BZkbFO text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-OIZ1kthaw3BZkbFO .actor-line{stroke:grey;}#mermaid-svg-OIZ1kthaw3BZkbFO .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO .sequenceNumber{fill:white;}#mermaid-svg-OIZ1kthaw3BZkbFO #sequencenumber{fill:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO .messageText{fill:#333;stroke:#333;}#mermaid-svg-OIZ1kthaw3BZkbFO .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OIZ1kthaw3BZkbFO .labelText,#mermaid-svg-OIZ1kthaw3BZkbFO .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-OIZ1kthaw3BZkbFO .loopText,#mermaid-svg-OIZ1kthaw3BZkbFO .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-OIZ1kthaw3BZkbFO .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-OIZ1kthaw3BZkbFO .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-OIZ1kthaw3BZkbFO .noteText,#mermaid-svg-OIZ1kthaw3BZkbFO .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-OIZ1kthaw3BZkbFO .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OIZ1kthaw3BZkbFO .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OIZ1kthaw3BZkbFO .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-OIZ1kthaw3BZkbFO .actorPopupMenu{position:absolute;}#mermaid-svg-OIZ1kthaw3BZkbFO .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-OIZ1kthaw3BZkbFO .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-OIZ1kthaw3BZkbFO .actor-man circle,#mermaid-svg-OIZ1kthaw3BZkbFO line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-OIZ1kthaw3BZkbFO :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}ClientConnectorParserPreprocessorOptimizerExecutorStorageEngine提交 SQL 查询权限校验、连接管理语法分析、语义分析检查字段/表、构造逻辑查询块生成并下发最优执行计划根据执行计划读取数据(可能命中索引)返回数据页或记录返回结果集ClientConnectorParserPreprocessorOptimizerExecutorStorageEngine
使用 EXPLAIN 查看执行计划
EXPLAIN SELECT * FROM users WHERE id = 1;
查看字段含义:
id
: 查询标识select_type
: 查询类型(SIMPLE/PRIMARY等)table
: 访问的表type
: 连接类型(ALL、index、range、ref、const 等)key
: 使用的索引rows
: 扫描的行数Extra
: 是否使用临时表、排序、是否回表等信息
查询性能影响因素
总结
一条 SQL 查询的完整内部执行流程如下:
- 客户端连接 → 建立连接并认证
- 解析 SQL → 词法/语法分析生成语法树
- 预处理 → 验证权限与对象合法性
- 优化器选择最优执行计划
- 执行器执行 SQL 逻辑
- 存储引擎读取数据
- 返回结果集给客户端