数据库

MySQL 8.4 索引实战:用 EXPLAIN 找出慢查询并验证优化

从慢查询场景出发,学习阅读 EXPLAIN、设计联合索引,并用 EXPLAIN ANALYZE 验证优化是否真正生效。

TY
Tycho
技术博主
• 2026-09-23 • 9 分钟阅读 • 3 次浏览
MySQL 8.4 索引实战:用 EXPLAIN 找出慢查询并验证优化

“给字段加索引”并不是可靠的优化方法。正确流程是:固定查询与数据规模,读取执行计划,根据过滤与排序顺序设计索引,再用实际执行数据验证。

练习建议:只在本地测试库操作。EXPLAIN ANALYZE 会真正执行语句,生产环境必须先评估成本。

一、建立可复现的查询场景

CREATE TABLE orders (
  id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
  customer_id BIGINT UNSIGNED NOT NULL,
  status VARCHAR(20) NOT NULL,
  total DECIMAL(10,2) NOT NULL,
  created_at DATETIME NOT NULL,
  INDEX idx_created_at (created_at)
);

SELECT id, total, created_at
FROM orders
WHERE customer_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

测试数据应覆盖多个客户、状态和日期。数据量太小会让优化器倾向全表扫描,不能代表真实业务。

二、先阅读 EXPLAIN,不急着建索引

EXPLAIN FORMAT=TREE
SELECT id, total, created_at
FROM orders
WHERE customer_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

传统表格输出中重点观察:

  • type:ALL 通常表示全表扫描;ref、range 往往更有选择性。
  • possible_keys 与 key:候选索引和最终采用的索引。
  • rows:预计扫描行数,不是返回行数。
  • Extra:关注 Using filesort、Using temporary 等额外成本。

三、按等值过滤与排序设计联合索引

CREATE INDEX idx_orders_customer_status_created
ON orders (customer_id, status, created_at DESC);

前两列对应等值过滤,第三列承接排序。联合索引不是字段集合,而是有顺序的查找结构;如果查询只按 status 过滤,这个索引未必合适。

四、用实际执行计划验证

EXPLAIN ANALYZE
SELECT id, total, created_at
FROM orders
WHERE customer_id = 42 AND status = 'paid'
ORDER BY created_at DESC
LIMIT 20;

比较优化前后的实际行数、循环次数和耗时。测试至少包含:高频客户、低频客户、没有结果的客户。只优化一个理想参数,可能造成错误结论。

五、检查索引成本与回滚

SHOW INDEX FROM orders;

-- 确认新索引无收益时再删除
DROP INDEX idx_orders_customer_status_created ON orders;

索引会占磁盘空间,也会增加 INSERT、UPDATE、DELETE 的维护成本。上线前记录基线,上线后观察慢查询、写入延迟和索引大小。

验证清单

  • 查询语义和返回结果没有变化。
  • 执行计划使用目标索引。
  • 扫描行数和实际耗时在多组参数下下降。
  • 没有重复或长期未使用的索引。
  • DDL 变更具备维护窗口和回滚方案。

常见误区

rows 变小就一定更快

不一定。还要观察随机 I/O、回表、排序、锁等待与缓存状态。

强制索引代替根因分析

数据分布会变化。优先修正索引与查询结构,只有充分验证后才考虑索引提示。

官方资料

MySQL 8.4 EXPLAIN 官方文档

TY

Tycho

热爱分享技术知识,帮助开发者成长。

评论 (0)

评论功能当前已关闭
暂无评论,快来抢沙发吧!