索引是数据库中对数据位置的快速映射,本质是有序数据结构(如B+树),存储字段值及对应主键或行指针;用于加速WHERE、ORDER BY、JOIN等操作,需遵循最左前缀原则,避免低选择性字段和过度创建。

索引是什么:数据库里的“目录”
索引不是数据本身,而是对数据位置的快速映射——就像书本末尾的索引页,查“B树”不用翻遍全书,直接跳到第42页。MySQL 中,INDEX 本质是一棵有序的数据结构(多数是 B+ 树),存储的是字段值 + 对应的主键或行指针。
没索引时,SELECT * FROM users WHERE name = 'Alice' 可能触发全表扫描;加了 INDEX(name) 后,引擎能直接定位匹配行,I/O 次数大幅下降。
什么时候必须建索引:WHERE、ORDER BY、JOIN 的常见场景
以下情况不建索引,性能容易掉坑里:
-
WHERE条件中高频出现的列,尤其是选择性高(重复值少)的字段,比如user_id、email -
ORDER BY created_at DESC—— 如果经常按时间倒序查最新10条,INDEX(created_at)能避免文件排序(Using filesort) -
JOIN的关联字段,如orders.user_id关联users.id,两边都建议有索引,否则驱动表小也扛不住被扫十几万次 - 注意:
LIKE 'abc%'可走索引,但LIKE '%abc'或LIKE '%abc%'基本失效(除非用全文索引)
复合索引怎么写:最左前缀原则不是玄学
INDEX(a, b, c) 实际上等价于三个索引:(a)、(a,b)、(a,b,c),但不包含 (b) 或 (b,c)。这意味着:
-
WHERE a = 1 AND b = 2✅ 走索引 -
WHERE a = 1 ORDER BY c✅ 可能用上索引做排序(覆盖a,c) -
WHERE b = 2❌ 不走索引(跳过了最左列a) - 如果查询常带
WHERE status = ? AND created_at > ?,把区分度高的放前面更稳,比如INDEX(status, created_at)比反过来更有效
索引不是越多越好:维护成本和隐式陷阱
每多一个索引,INSERT/UPDATE/DELETE 都要同步更新 B+ 树,写放大明显。更隐蔽的问题包括:
- 字符串字段没指定长度就建索引:如
VARCHAR(255)直接INDEX(content),MySQL 默认取前 767 字节(utf8mb4 下约 191 字符),可能截断导致索引失效 - 频繁
UPDATE的字段建索引,会引发大量页分裂和碎片,SHOW INDEX FROM tbl查看Cardinality是否严重偏低 - 唯一性低的字段(如
gender只有 'M'/'F')建普通索引意义很小,优化器大概率直接放弃使用
真正难的不是建索引,是判断哪些查询值得索引、哪些该用覆盖索引、哪些其实该改 SQL 或加缓存——执行计划(EXPLAIN)里那几行 type 和 key 才是关键线索。










