索引拆分本质是依查询频率、组合及数据分布,优先为高频高选择性字段建单列索引,再按“等值在前、范围在后”设计联合索引,并利用覆盖索引减少回表,定期清理冗余索引。
理解索引拆分的本质
索引拆分不是简单地把一个大索引改成多个小索引,而是根据查询条件的使用频率、组合方式和数据分布,把高频、高选择性的过滤字段优先独立建索引,再按需补充联合索引。核心目标是让每个关键查询都能命中“最短、最匹配”的索引路径,避免全表扫描或索引失效。
先识别哪些字段值得单独建索引
重点关注
WHERE 子句中独立出现、且有较高区分度(如用户ID、订单状态、创建日期)的字段
。例如:
user_id = ?
出现频繁且基数大 → 单独建 B+ 树索引
status IN ('paid', 'shipped')
虽然范围小,但常作为查询入口 → 可单列索引(配合覆盖优化)
created_at > '2024-01-01'
时间范围查询多 → 单独索引 + 注意避免在它上面加函数(如 DATE(created_at))
联合索引要按“过滤强度+顺序”设计
联合索引的字段顺序不能随意。原则是:
高选择性字段在前,等值查询字段在前,范围查询字段放最后
。比如常见复杂查询:
php版微信js-sdk支付接口类
php版微信js-sdk支付接口类
下载
WHERE user_id = ? AND status = ? AND created_at > ?
→ 推荐索引:
WHERE status = ? AND category = ? ORDER BY updated_at DESC
→ 若只查少量结果,可建
支持过滤+排序
避免
这类把范围字段放前面的组合——它无法有效支持
user_id = ?
单独查询
用好覆盖索引减少回表
如果查询只涉及少数几个字段(如
SELECT id, status, updated_at FROM orders WHERE user_id = ?
),可在联合索引中直接包含 SELECT 字段:
建索引:
—— 注意 id 是主键,自动包含,但显式写出更清晰
这样查询完全走索引,不回主键聚簇索引,显著降低 I/O
但别过度覆盖:字段越多,索引体积越大,写入越慢;权衡读写比
定期验证和精简冗余索引
运行
SHOW INDEX FROM table_name
和
SELECT * FROM sys.schema_unused_indexes
(MySQL 8.0+)查看未被使用的索引。特别注意:
和
共存时,单列索引
往往可删(除非
基数极低或查询只查
)
长期没命中的联合索引(尤其含三个以上字段)建议归档评估,改用更聚焦的组合
用
EXPLAIN FORMAT=JSON
查看 key_len、used_key_parts,确认实际用了哪些索引字段
(user_id, status, created_at)(status, category, updated_at)(created_at, user_id)(user_id, status, updated_at, id)(a)(a, b)(a)ba