Files
Hugo/content/blog/database-indexing.md
T

2.1 KiB
Raw Blame History

title, date, draft, poet, description, tags
title date draft poet description tags
数据库索引优化实战 2026-05-10T16:00:00+08:00 false 众里寻他千百度, 蓦然回首,那人却在,灯火阑珊处。 ——辛弃疾,中国,1140–1207 慢查询分析、联合索引的最左前缀原则、覆盖索引与回表的性能差异。几个真实 SQL 优化案例,从几秒降到毫秒级。
数据库
SQL
性能

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。

索引不是越多越好——每个索引都会拖慢写入速度并占用磁盘空间。建索引前问自己:这个查询的执行频率值得一个索引吗?