索引与失效
→ 返回 MySQL
B+ 树(InnoDB)
- 数据在叶子节点,叶子双向链表支持范围扫描
- 非叶子只存键,扇出高、树矮
索引类型
| 类型 | 说明 |
|---|---|
| 聚簇索引(主键) | 叶节点 = 完整行 |
| 二级索引 | 叶节点 = 索引列 + 主键,可能回表 |
| 唯一索引 | 允许多个 NULL |
| 联合索引 | 最左前缀 |
| 覆盖索引 | Extra: Using index |
最左前缀
索引 (a, b, c):
| 条件 | 使用 |
|---|---|
a = ? | ✅ a |
a = ? AND b = ? | ✅ a, b |
a = ? AND c = ? | ⚠️ 仅 a |
b = ? | ❌ |
a > ? AND b = ? | ⚠️ a 范围后 b 常失效 |
设计:等值列在前,范围/排序在后,如 (user_id, created_at)。
索引失效(重点)
1. 对索引列使用函数
-- ❌
WHERE YEAR(created_at) = 2024
-- ✅
WHERE created_at >= '2024-01-01' AND created_at < '2025-01-01'8.0+ 生成列索引:
ALTER TABLE t ADD COLUMN created_year INT AS (YEAR(created_at)) STORED,
ADD INDEX idx_year (created_year);2. 隐式类型转换
-- phone VARCHAR,传入数字 → 索引失效
WHERE phone = 13800138000
-- ✅
WHERE phone = '13800138000'3. LIKE
WHERE name LIKE 'Alice%' -- ✅ 前缀
WHERE name LIKE '%Alice' -- ❌大文本用 FULLTEXT 或 Elasticsearch。
4. OR / NOT
-- ✅ 拆 UNION
SELECT * FROM t WHERE id = 1
UNION ALL
SELECT * FROM t WHERE name = 'x' AND id <> 1;5. ORDER BY / GROUP BY
-- 索引 (user_id, created_at)
WHERE user_id = 1 ORDER BY created_at; -- ✅
WHERE user_id IN (1,2,3) ORDER BY created_at; -- ⚠️ 常 filesort6. 优化器选全表扫
选择性太低、统计过期 → ANALYZE TABLE orders;
7. 字符集不一致
JOIN/WHERE 两侧 collation 不同 → 可能 CONVERT。统一 utf8mb4_unicode_ci。
自查清单
| 检查 | 动作 |
|---|---|
EXPLAIN.key 为 NULL | 看 type、rows |
Using filesort / temporary | 调索引或 SQL |
| 函数包列 | 改范围或生成列 |
| 隐式转换 | SHOW WARNINGS |