本文面向 MySQL 8.0 的工程团队,目标是把“计划成本”与“真实耗时”打通,形成可复现、可回归的性能画像与优化闭环。


## 适用版本与前提


  • EXPLAIN ANALYZE 支持:MySQL 8.0.18+(实际运行并返回每步耗时与行数)。
  • 存储引擎:InnoDB(默认),示例依赖其索引与统计信息。
  • 基础参数建议:
  • `optimizer_switch` 使用默认,避免关闭影响生成计划判断。
  • 开启 `performance_schema` 便于采集全局指标(可选)。

## 示例表与索引(可直接复现)


CREATE TABLE orders (
  id BIGINT PRIMARY KEY,
  user_id BIGINT NOT NULL,
  status TINYINT NOT NULL,
  amount DECIMAL(10,2) NOT NULL,
  created_at TIMESTAMP NOT NULL,
  KEY idx_user_created (user_id, created_at),
  KEY idx_status_created (status, created_at)
) ENGINE=InnoDB;

-- 准备 10 万行数据(略)。确保两个组合索引均被命中于不同查询场景。

## EXPLAIN 与 EXPLAIN ANALYZE 的差异


  • `EXPLAIN`:显示“计划”层面的访问类型(`type`)、估计行数(`rows`)、过滤率(`filtered`)、可能使用索引(`possible_keys`)等,不执行查询。
  • `EXPLAIN ANALYZE`:实际执行查询,并返回每个算子(operator)的真实耗时、读取行数、回表次数与 buffer 命中情况(在 8.0 中以文本树形式呈现)。

示例对比:


EXPLAIN SELECT * FROM orders WHERE user_id = 1001 AND created_at >= '2024-01-01' LIMIT 50;

EXPLAIN ANALYZE SELECT * FROM orders WHERE user_id = 1001 AND created_at >= '2024-01-01' LIMIT 50;

观察要点(可验证):


  • 计划估算行数(`rows`)与实际读取行数差距是否过大(统计信息失真信号)。
  • `Using index`/`Using where` 的组合是否合理;是否出现 `filesort` 或 `range` 扫描导致额外成本。
  • LIMIT 是否在上游就“剪枝”(减少下游回表与过滤工作)。

## 典型场景画像与优化


场景 A:等值 + 范围检索命中联合索引(优先走最左前缀)


EXPLAIN ANALYZE SELECT id, amount
FROM orders
WHERE user_id = 1001
  AND created_at BETWEEN '2024-01-01' AND '2024-03-31'
ORDER BY created_at DESC
LIMIT 100;

优化要点:


  • 选择性高的列放在组合索引前部(如 `user_id, created_at`),避免产生 `filesort` 与多余回表。
  • 若 ORDER BY 与索引顺序一致且覆盖列足够,可形成覆盖扫描,显著降低 I/O。

场景 B:状态聚合与过滤(可能触发范围扫描)


EXPLAIN ANALYZE SELECT status, COUNT(*)
FROM orders
WHERE created_at >= '2024-01-01'
GROUP BY status;

优化要点:


  • 针对 `status, created_at` 的联合索引可降低回表与范围扫描代价。
  • 如需更优 COUNT 聚合,可评估物化统计或异步聚合表(业务允许前提下)。

## 统计信息与直方图(误差归因)


  • 更新统计:`ANALYZE TABLE orders;`(更新索引基数与分布,验证前后计划是否变化)。
  • 直方图(8.0):可为非索引列建立分布估计,改善选择性判断。

-- 为 amount 建立直方图(示例)
ANALYZE TABLE orders UPDATE HISTOGRAM ON amount WITH 100 BUCKETS;
SHOW HISTOGRAM ON orders amount;

校验点:


  • 重新执行 `EXPLAIN/EXPLAIN ANALYZE`,验证 `rows`/过滤率与实际读取行数的收敛情况。
  • 如计划仍不稳定,检查数据倾斜与列相关性(联合索引列间强相关时,估算易失真)。

## 回归验证与基线建立


  • 指标采集:记录关键查询的 `query_time`、`rows_examined`、返回行数与 `EXPLAIN ANALYZE` 文本摘要。
  • 基线方法:
  • 选取 3–5 个核心查询作为基准,建立“索引/统计/数据规模”三维度的回归用例。
  • 每次发布前后对比 p95/p99 耗时与 `rows_examined` 是否回归到基线范围内。
  • 工具协同:结合 `performance_schema`/慢查询日志与 `pt-query-digest` 汇总热点。

## 注意事项


  • `EXPLAIN ANALYZE` 会实际执行查询,注意在生产环境评估代价与加 LIMIT/条件护栏。
  • 统计信息更新可能改变计划,需绑定到发布/迁移流程,并进行上线前回归。
  • 对跨分区或超大范围扫描的查询,优先评估归档/分区策略而非仅靠索引微调。

## 结语


通过将 EXPLAIN 的“计划视角”与 EXPLAIN ANALYZE 的“真实执行”打通,并结合统计信息与直方图的校准,可以把优化从“拍脑袋”转为“数据驱动”。用少量核心基准维持稳定的性能画像,是长期可维护的工程实践。



点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部