索引是什么:数据库里的“目录”
索引不是数据本身,而是对数据位置的快速映射——就像书本末尾的索引页,查“B树”不用翻遍全书,直接跳到第42页。MySQL 中,
INDEX本质是一棵有序的数据结构(多数是 B+ 树),存储的是字段值 + 对应的主键或行指针。
没索引时,
SELECT * FROM users WHERE name = 'Alice'可能触发全表扫描;加了
INDEX(name)后,引擎能直接定位匹配行,I/O 次数大幅下降。
什么时候必须建索引:WHERE、ORDER BY、JOIN 的常见场景
以下情况不建索引,性能容易掉坑里:
WHERE条件中高频出现的列,尤其是选择性高(重复值少)的字段,比如
user_id、
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才是关键线索。
