MySQL实际执行代价需通过真实指标判断:EXPLAIN的rows是预估扫描行数;performance_schema或SHOW PROFILE看真实耗时;optimizer_trace揭示优化器决策;Handler状态和锁指标反映隐藏开销。
怎么看 MySQL 实际执行的查询代价
MySQL 本身不直接暴露“查询代价”的数值(比如 12.7 cost 这种),EXPLAIN 输出里的 cost 列仅在启用 optimizer_trace 或使用 EXPLAIN FORMAT=JSON 时才可能间接体现,且是优化器预估值,不是真实开销。真正可观察、可对比的代价,得看实际执行行为:
-
EXPLAIN中的rows值——优化器预估扫描行数,越接近真实扫描量,预估越可信;明显偏高通常意味着统计信息过期或缺少有效索引 - 开启
profiling(已弃用)或更推荐用performance_schema查events_statements_history_long,看TIMER_WAIT(纳秒级真实执行耗时)和LOCK_TIME - 用
SHOW PROFILE FOR QUERY N(需先SET profiling = 1)看各阶段耗时分布,比如Copying to tmp table或Sorting result占比高,说明临时表或排序成了瓶颈
为什么 EXPLAIN 的 key_len 比预期小
key_len 显示的是 MySQL 实际用到的索引字节数,不是定义长度。它小,往往意味着索引没被充分利用,常见原因有:
- 索引列存在
NULL,且查询条件是IS NULL或未加NOT NULL约束,导致无法使用最左前缀匹配 - 查询条件用了函数或表达式,如
WHERE YEAR(created_at) = 2024,即使created_at有索引,key_len也会是 0 - 联合索引中,中间某列用了范围查询(
>,BETWEEN,LIKE 'abc%'),后续列就失效,key_len只计算到范围列为止 - 字符集不同导致隐式转换,比如
utf8mb4列与utf8字符串比较,索引可能部分失效
如何用 optimizer_trace 看优化器真实决策过程
这是唯一能看清 MySQL “怎么算出这个执行计划”的方式,但默认关闭,且有性能开销,只应在调试时临时启用: