一张表索引数量应由查询模式、写入频率和字段选择性共同决定;优先为高频where/join/order by字段建索引,避免低区分度字段单独建索引,慎用冗余复合索引,并通过explain持续验证索引命中情况。

一张表不该有固定数量的索引,而应由查询模式、写入频率和字段选择性共同决定。盲目堆砌索引反而拖慢写入、浪费空间、干扰优化器选型。
哪些列值得建索引?看实际 WHERE / ORDER BY / JOIN 条件
只给真正被高频过滤或排序的列建索引。比如:
-
user_id出现在 80% 的WHERE条件中 → 优先建单列索引或作为复合索引首列 -
status只在管理后台偶尔查 → 别单独建索引,除非搭配高选择性字段组成复合索引 -
created_at常和user_id一起用于分页查询 → 考虑(user_id, created_at)复合索引,而非两个单列索引
复合索引别重复覆盖前缀,否则白建
例如已有 idx_user_id_created_at,再建 idx_user_id 就是冗余——MySQL 用前者就能满足纯 user_id 等值查询。检查冗余的方法:
- 用
SHOW INDEX FROM table_name查所有索引列顺序 - 对每个新索引,确认它是否能被现有索引的最左前缀覆盖
- 特别警惕
(a)、(a,b)、(a,b,c)这类“嵌套式”冗余
低选择性字段单独建索引基本没用
像 gender、is_deleted 这类只有 2–3 个取值的字段,单独建索引通常不会走(优化器判断全表扫描更快)。验证方式:
- 执行
SELECT COUNT(DISTINCT gender) / COUNT(*) AS selectivity FROM users; - 结果
(即 5%)时,基本不建议单独建索引 - 若必须加速这类查询,考虑和高选择性字段组合成复合索引,如
(is_deleted, user_id)
写多读少的表,索引要更克制
日志表、操作流水表这类每秒写入数百次的表,加一个索引可能让 INSERT 变慢 20%–50%。此时优先保证写入吞吐,读查尽量走时间分区或归档策略,而不是靠索引硬扛。
真正容易被忽略的是:索引不是“建了就生效”,它需要配合 EXPLAIN 验证是否被命中,且随数据分布变化会失效——上周有效的索引,下周数据倾斜后可能就被优化器弃用了。











