← ClaudeAtlas

mysql-indexlisted

Use when diagnosing slow SQL, creating or changing secondary indexes, EXPLAIN, 最左前缀, covering index, or implicit conversion. Do not use for sharding or table status-machine design.
1398281322-a11y/java-backend-guardrails · ★ 2 · API & Backend · score 71
Install: claude install-skill 1398281322-a11y/java-backend-guardrails
# MySQL 索引 ## When to Invoke 慢查询、`EXPLAIN`、加索引、分页深翻、订单列表按用户+时间查。 ## When NOT 分库分表、选分片键 → `sharding`。建表字段/唯一键/归档 → `table-design`。 ## 风险(面试考点) InnoDB 二级索引是 B+ 树。联合索引最左前缀:`(user_id, created_at)` 能用 `user_id`,不能单独用 `created_at`。回表:二级索引找到主键再回聚簇。覆盖索引:SELECT 列都在索引里可避免回表。隐式转换(`varchar` 列用数字比)会让索引失效。函数包列(`DATE(created_at)=`)同样失效。 面试常说「RR 靠间隙锁防幻读」——那是锁,不是索引本身;本 skill 不展开。当前读/间隙锁见业务里 `SELECT FOR UPDATE` 时再单独处理。 ## 适用场景 - `WHERE user_id=? ORDER BY created_at DESC LIMIT 20` - 核销列表:`merchant_id + status + created_at` - 回调查重:应靠 UNIQUE,不是普通二级索引 ## 方案选型(轻量优先) | 场景 | 默认索引 | |------|----------| | 等值 + 时间排序 | `(user_id, created_at)` | | 等值 + 过滤 + 时间 | `(merchant_id, status, created_at)` | | 唯一业务键 | UNIQUE,不当成普通 INDEX | | 低区分度列(status 单独) | 不要单建;放到联合索引第二列 | | 深分页 | 延迟关联 / 记上次 ID,不 `LIMIT 100000,20` | 先 `EXPLAIN`,再加索引。禁止凭感觉给每个查询字段都建单列索引。 ## 默认方案 ```sql EXPLAIN SELECT id, order_no, created_at FROM t_order WHERE user_id = ? AND created_at >= ? ORDER BY created_at DESC LIMIT 20; -- 期望:type=range, key=idx_user_created, Extra 尽量 Using index 或至少非 filesort 全表 ``` ```sql ALTER TABLE t_order ADD KEY idx_user_created (user_id, created_at); ``` 分页: ```sql -- 用上一页最小 id,不要大 offset WHERE user_id = ? AND id < #{lastId} ORDER BY id DESC LIMIT 20; ``` 隐式转换: ```sql -- 列是 VARCHAR 单号 WHERE order_no = 123 -- 可能失效 WHERE order_no = '123' -- 正确 ``` ## 反例 错���:`WHERE DATE(created_at) = '2026-09-01'`。 正确:`created_at >= '2026-09-01' AND created_at < '2026-09-02'`。 错误:`OR` 两边不同列导致全表;或 `LIKE