索引设计怎么想
索引设计可以顺着五个问题走:哪些查询是热点、条件列的选择性够不够、排序与分组列能否顺带覆盖、写入放大的代价能否接受、现有索引能不能改造而不是新增。这五个问题覆盖了索引设计最容易出错的地方——问题通常不是缺索引,而是索引建错位置、建得过多,或者与真实查询形态不匹配。
基本信息
| 核心问题 | 热点查询、选择性、覆盖、写放大、能否改造 |
|---|---|
| 列顺序原则 | 等值条件在前,范围条件次之,排序列最后 |
| 选择性要求 | 高区分度的列优先 |
| 覆盖策略 | 让高频查询只读索引不必回表 |
| 数量控制 | 控制单表索引数量以平衡写入代价 |
| 清理要求 | 冗余索引定期清理 |
设计要点
- 选择性高的列优先:区分度越大过滤效果越好
- 复合索引按等值条件、范围条件、排序需求的顺序排布
- 高频查询尽量被单个复合索引完全覆盖,避免回表
- 控制单表索引数量,写入代价与索引数量成正比
- 冗余索引定期清理:前缀相同的索引往往可以合并审视
索引现状盘点
索引现状盘点
SELECT INDEX_NAME, GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) AS cols,
MAX(CARDINALITY) AS card, MAX(NON_UNIQUE) AS non_unique # 卡片度反映选择性
FROM information_schema.statistics
WHERE TABLE_SCHEMA='appdb' AND TABLE_NAME='orders'
GROUP BY INDEX_NAME; # 一眼看出各索引包含哪些列、顺序如何设计对照
| 场景 | 推荐做法 | 原因 |
|---|---|---|
| 等值加排序 | 复合索引把等值列放前、排序列放后 | 排序可直接借用索引顺序 |
| 多条件查询 | 把最常用的组合建成一个复合索引 | 减少索引数量并提升命中率 |
| 低选择性列 | 不单独建索引 | 优化器基本不会使用 |
| 长字符串列 | 用前缀索引并验证区分度 | 完整索引体积过大 |
| 写多读少的表 | 严格控制索引数量 | 每个索引都会拖慢写入 |
| 前缀重复的索引 | 合并或删除其中一个 | 冗余索引只增加成本 |
索引不是越多越好:每个索引都是写入成本与磁盘成本,应按真实查询矩阵设计,而不是凭直觉逐字段添加。
低选择性列单独建索引(例如性别、状态枚举)基本不会带来收益:优化器通常直接放弃使用,只留下空间与写入开销。
设计复核清单
- 列出热点查询并按耗时排序
- 核对每个索引是否对应真实语句
- 检查复合索引的列顺序是否符合最左前缀
- 评估新增索引带来的写入代价
- 定期清理冗余与未被使用的索引
索引设计要跟着查询形态演进:业务查询变了而索引没变,就会出现索引闲置与写入变慢同时发生的局面,定期按慢查询清单回看索引是必要动作。