# MySQL 索引规约

> 来源: Java开发手册（嵩山版）— 五(二) 索引规约

## 【强制】规则

### 1. 唯一特性字段建唯一索引

即使组合字段也必须建唯一索引。根据墨菲定律，没有唯一索引必然产生脏数据。

### 2. 超过三表禁止 join

需要 join 的字段，数据类型保持绝对一致；被关联的字段需要有索引。

### 3. varchar 索引指定长度

没必要对全字段建索引。长度为 20 的索引区分度可达 90% 以上。

> **公式**: `count(distinct left(列名, 索引长度))/count(*)`

### 4. 严禁左模糊/全模糊搜索

页面搜索严禁 `LIKE '%xxx'` 或 `LIKE '%xxx%'`。B-Tree 最左前缀匹配，左边值未确定无法使用索引。

## 【推荐】规则

### 5. order by 利用索引有序性

`order by` 最后的字段是组合索引的一部分，放在索引组合顺序的最后。

> **反例**: `WHERE a>10 ORDER BY b;` 索引 a_b 无法排序（范围查询破坏了有序性）。

### 6. 覆盖索引避免回表

explain 结果 extra 列出现: `using index`。

### 7. 延迟关联优化分页

> **正例**:
> ```sql
> SELECT t1.* FROM 表1 as t1,
>   (select id from 表1 where 条件 LIMIT 100000,20) as t2
>   where t1.id=t2.id;
> ```

### 8. SQL 优化目标

`consts` > `ref` > `range`，至少达到 range。

| 级别 | 说明 |
|------|------|
| consts | 单表最多一个匹配行（主键/唯一索引） |
| ref | 普通索引 |
| range | 索引范围检索 |

> **反例**: `type=index` 是全扫描，比 range 还低。

### 9. 组合索引区分度最高放左边

等号条件的列优先放在索引最前列。

> **正例**: `where c>? and d=?` → 建组合索引 `idx_d_c`

### 10. 防止隐式转换

字段类型不同导致隐式转换，索引失效。

## 【参考】

### 11. 避免极端误解

- 宁滥勿缺 — 不是每个查询都需要索引
- 吝啬创建 — 索引确实消耗空间、拖慢写入
- 抵制惟一索引 — 应用层"先查后插"不如数据库层面约束
