覆盖索引必须同时包含WHERE等值条件列和SELECT返回的所有列,缺一不可;例如查询SELECT user_id, status, amount FROM orders WHERE user_id = 123 AND status = 'paid',需建(user_id, status, amount)联合索引。

覆盖索引到底要包含哪些字段?
覆盖索引不是“把WHERE里出现的列都加进去”就行,它必须同时满足两个硬条件:WHERE中的等值条件列 + SELECT中要返回的所有列。缺一不可。
常见错误是只顾WHERE条件,忘了SELECT字段。比如查询 SELECT user_id, status, amount FROM orders WHERE user_id = 123 AND status = 'paid',只建 (user_id, status) 索引是不够的——amount 没在索引里,仍要回表。
- 正确做法:建
(user_id, status, amount),顺序按最左前缀原则排列(user_id最常等值过滤且选择性高,放最左) - 如果还要支持
ORDER BY created_at,且 MySQL 版本 ≥ 8.0,可扩展为(user_id, status, created_at, amount),但注意created_at必须紧接在等值列之后,且显式声明方向(如created_at DESC) -
SELECT *基本无法走覆盖索引,除非你给整张表所有字段建联合索引——这既不现实,也严重拖慢写性能
为什么EXPLAIN显示“Using index”却还是慢?
EXPLAIN 的 Extra 列出现 Using index,只代表“用了索引”,不等于“覆盖了”。真正确认覆盖索引,得盯死三件事:
-
key字段非空 → 索引被选中(否则压根没走) -
key_len值要匹配预期字节数 → 比如user_id是INT(4 字节),status是VARCHAR(20)(utf8mb4 下最多 80 字节),amount是DECIMAL(10,2)(通常 5 字节),那key_len = 4+80+5 = 89才说明三列全用上了 -
Extra必须是Using index(不是Using where; Using index)→ 后者只是说 WHERE 条件用了索引,但 SELECT 字段仍需回表
如果 rows 接近全表行数,哪怕 key_len 对了、Extra 也写了 Using index,也大概率是索引列选择性太差(比如 status 只有 2–3 个值),优化器干脆放弃走索引。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
多条件筛选时,组合索引列顺序怎么排?
顺序不是按 SQL 里写的先后,而是按查询模式的实际使用频率和选择性来排。核心原则就一条:把最常用于等值过滤(= 或 IN)、且值分布最分散的列放最左。
- 举例:用户订单表中,
user_id平均每用户 50 单,status有 4 种状态,pay_channel有 8 种渠道。那么user_id选择性远高于后两者,应放首位 - 如果经常查
WHERE status = ? AND pay_channel = ?,但几乎不带user_id,那(status, pay_channel)才合理;反之若总带user_id,那(user_id, status, pay_channel)更稳 - 范围查询(
>,,BETWEEN)后面的列,即使出现在索引定义里,也无法被用于索引查找(只能用于排序或覆盖),所以别把它放在等值列中间
哪些写法会让覆盖索引直接失效?
再好的索引,SQL 写错一个字符就白搭。以下操作会强制回表,哪怕索引结构完全匹配:
- 对索引列用函数:比如
WHERE YEAR(created_at) = 2024→ 改成WHERE created_at >= '2024-01-01' AND created_at - 隐式类型转换:字符串字段
order_no是VARCHAR,却写WHERE order_no = 12345→ 改成WHERE order_no = '12345' - LIKE 以通配符开头:
WHERE name LIKE '%john%'→ 无法利用索引,LIKE 'john%'才可以 - SELECT 中混入未索引字段:
SELECT user_id, amount FROM orders WHERE user_id = 123能覆盖,但加个email就破功,除非你也把email加进索引
最容易被忽略的是 ORDER BY 和 GROUP BY 字段——它们不参与 WHERE 过滤,但若想避免 filesort,就必须作为索引后缀显式包含,且顺序/方向要对齐。这点在分页和统计类查询里特别致命。










