一、先分清索引类型
| 类型 | 说明 |
|---|---|
| 聚簇索引 | InnoDB 主键即聚簇,叶子存整行,每张表只有一个 |
| 二级索引 | 叶子存主键值,查非索引列需回表 |
| 覆盖索引 | 查询列都在索引里,无需回表,最快 |
| 联合索引 | 多列组合,遵循最左前缀 |
二、最左前缀原则
联合索引 (a, b, c) 能命中:a、(a,b)、(a,b,c);跳过头列如 WHERE b=1 用不上索引。因此把区分度高、最常用作过滤的列放最左。
三、索引失效的常见写法
| 写法 | 后果 |
|---|---|
| 对索引列做函数/运算 | WHERE YEAR(created) = 2024 失效 |
| 隐式类型转换 | 字符串列用数字查,触发转换失效 |
| 前导模糊 | LIKE ‘%abc’ 失效,’abc%’ 可用 |
| 范围后列失效 | (a, b) 中 a 用范围,b 不再走索引 |
| OR 含非索引列 | 整体可能放弃索引 |
-- 命中索引(走 a 前缀)
SELECT id FROM t WHERE a = 1 AND b = 2;
-- 失效(对列用了函数)
SELECT id FROM t WHERE DATE(created) = '2024-01-01';
四、覆盖索引与回表
尽量让高频查询走覆盖索引,避免回表 IO。例如为 SELECT user_id, status FROM orders WHERE user_id=? 建 (user_id, status) 联合索引即可覆盖。
五、前缀索引与选择性
长字符串(如 URL、邮箱)用前缀索引省空间:ALTER TABLE t ADD INDEX idx(url(20)),但前缀无法用于 ORDER BY / GROUP BY 的范围。权衡:选择性 = 不重复值/总数,越接近 1 越好。
六、EXPLAIN 看什么
- type:从好到差 const > eq_ref > ref > range > index > ALL,ALL 是是全表扫描;
- key:实际用的索引;
- rows:预估扫描行数,越小越好;
- Extra:
Using index覆盖、Using filesort需优化、Using temporary危险。
索引优化的第一性原理:让查询尽可能用上索引、少回表、少扫描。EXPLAIN 是你和 MySQL 优化器对话的窗口。