数据库索引优化实战
2026-05-10
EXPLAIN 是 DBA 的眼睛。看 type 字段从 ALL 变成 ref 是最有成就感的事。
从慢查询开始
一切优化从定位问题开始。打开 MySQL 的慢查询日志(slow_query_log),设置 long_query_time = 0.1,跑一段时间后分析。PostgreSQL 用 pg_stat_statements 扩展,同样有效。
拿到慢查询,先 EXPLAIN 看执行计划。关注几个关键字段:
| 字段 | 含义 | 目标 |
|---|---|---|
| type | 访问类型 | 至少到 range,最好到 ref/const |
| key | 使用的索引 | 不为 NULL |
| rows | 扫描行数 | 越小越好 |
| Extra | 额外信息 | 避免 Using filesort / Using temporary |
最左前缀原则
联合索引是最容易出错的地方。假设索引是 (a, b, c):
WHERE a = 1✅ 用到索引WHERE a = 1 AND b = 2✅ 用到索引WHERE b = 2❌ 用不到WHERE a = 1 AND c = 3⚠️ 只用到了 a 列
排序也受这个规则约束。ORDER BY a, b 没问题,ORDER BY b, c 就需要额外排序。
覆盖索引
如果查询需要的所有列都在索引里,就不需要回表取数据。Extra 列显示 Using index 就是覆盖索引。对一个高频查询,覆盖索引能减少大量随机 I/O。
代价是索引变大了。不要为了覆盖索引把所有列都塞进索引——算一笔写入性能和存储空间的账。
真实案例
某个订单列表查询,原始 SQL 跑了 8 秒。EXPLAIN 一看,type: ALL,全表扫描 200 万行。加了 (user_id, created_at) 联合索引后,type: ref,扫描 20 行,耗时 12ms。
索引不是越多越好——每个索引都会拖慢写入速度并占用磁盘空间。建索引前问自己:这个查询的执行频率值得一个索引吗?