mysql如何执行SQL查询_mysql查询执行流程解析

13次阅读

mysql 执行 select 语句需经词法语法分析、查询重写、逻辑优化、物理优化、执行五个阶段;各阶段异常会导致慢查或报错,需结合 slow_log、show profile 及统计信息更新等定位根因。

mysql 如何执行 SQL 查询_mysql 查询执行流程解析

MySQL 执行 SQL 查询时,到底发生了什么

一条 SELECT 语句发给 MySQL,并不等于立刻去磁盘读数据。它会先走一套完整的解析、优化、执行链路,中间任何一环出问题都可能导致慢、错、甚至拒绝执行。

SQL 从输入到结果的五个关键阶段

MySQL 服务端收到查询后,按顺序经历以下阶段(可通过 EXPLAIN FORMAT=TREE 或开启 optimizer_trace 观察):

  • 词法与语法分析 :检查 SELECT * FROM t WHERE id = ? 是否符合 MySQL 语法规则;非法字段名、缺失逗号、错误关键字都会在这里报错,如 ERROR 1054 (42S22): Unknown column 'xxx' in 'field list'
  • 查询重写 :将视图展开、去除无用的 ORDER BY(如子查询中)、合并常量条件(WHERE 1=1 AND a=5WHERE a=5
  • 逻辑优化(Logical Optimization):基于规则改写,比如谓词下推(把 WHERE 条件尽可能下推到 JOIN 或子查询内部)、等价变换(a > 5 AND a → <code>a BETWEEN 6 AND 9
  • 物理优化(Cost-based Optimization):生成多个执行计划候选(如用 idx_a 还是 idx_b,是否走索引合并),估算每个计划的 IO/ 内存 /CPU 开销,选成本最低的——这就是为什么 EXPLAIN 显示的 key 不一定和你预期一致
  • 执行引擎调用 :调用存储引擎接口(如 InnoDB 的 ha_innobase::index_read()ha_innobase::rnd_next()),真正读取数据页、加锁、返回记录

为什么 EXPLAIN 显示走了索引,但实际还是慢

常见误解是“有 key 就快”,其实不然。几个关键干扰点:

  • 索引扫描行数(rows)远大于实际返回行数(filtered 值低),说明大量回表或无效过滤,比如 WHERE status IN ('A','B','C') AND create_time > '2023-01-01',但只有 status 有索引,create_time 条件被当成 post-filter 处理
  • 使用了索引但触发了 Using filesortUsing temporary,意味着排序或分组没走索引,而是在内存或磁盘临时表里做
  • 统计信息过期(ANALYZE TABLE 没跑过),优化器误判数据分布,选了全索引扫描而非范围扫描
  • 隐式类型转换导致索引失效,例如字段是 VARCHAR,但查询写了 WHERE phone = 13800138000(数字字面量),MySQL 自动转成 CAST(phone AS DOUBLE),索引无法使用

如何快速定位执行卡在哪一步

别只看 EXPLAIN,结合运行时指标交叉验证:

  • 开启 slow_query_log 并设置 long_query_time = 0,配合 log_output = 'TABLE',查 mysql.slow_log 看真实耗时分布(Lock_time, Rows_sent, Rows_examined
  • 对单条查询加 /*+ MAX_EXECUTION_TIME(1000) */ 防止长尾拖垮连接池
  • SHOW PROFILE FOR QUERY N(需先 SET profiling = 1)查看各阶段耗时,重点关注 statistics(优化器耗时)、executing(执行本身)、Sending data(构造结果集,常被误认为 IO)
  • InnoDB 层可查 INFORMATION_SCHEMA.INNODB_TRXINNODB_LOCK_WAITS,确认是否被锁阻塞而非真慢

执行流程不是黑盒,但每个环节的偏差都可能被放大。最常被跳过的其实是更新统计信息和检查隐式转换——这两步花 30 秒,往往比调优 SQL 本身更有效。

text=ZqhQzanResources