← 回笔记流

理解数据库索引:为什么它能让查询快几个数量级

后端面试高频题,也是实际开发里最容易踩性能坑的地方。这篇从直觉讲起。

没有 index 时发生了什么

SELECT * FROM users WHERE email = 'a@b.com';

没有索引,数据库只能做全表扫描:从第一行扫到最后一行,逐行比对。一万行还好,一亿行就是灾难。

索引 = 一本目录

索引的本质,是拿空间换时间:额外存一份“按某个字段排好序、且指向原数据位置”的数据结构。就像书的目录 —— 想找某个词,不用翻遍全书,先查目录拿到页码,直接翻过去。

绝大多数关系库用的是 B+ 树:一棵平衡的多叉树,查找复杂度是 O(log n)。一亿行的表,找一条记录大约只要 27 次比较左右,而不是一亿次。

最左前缀原则(联合索引最容易踩的坑)

建一个联合索引 (a, b, c),它实质上是对 a, b, c 这个组合排好序。能利用它的查询必须从最左列开始连续命中:

-- 能用到:
WHERE a = 1
WHERE a = 1 AND b = 2
WHERE a = 1 AND b = 2 AND c = 3

-- 用不到(缺了 a 这个前缀):
WHERE b = 2
WHERE b = 2 AND c = 3

直觉上:字典按“姓 + 名”排序,你只知道名,字典帮不了你,因为它不是按名排的。

什么时候索引会“失效”

加了索引不代表查询一定走索引。常见失效场景:

  • 对索引列用函数:WHERE YEAR(created_at) = 2026 —— 对列做了运算,排序结构用不上。改成区间比较 created_at >= '2026-01-01'
  • 隐式类型转换:列是字符串,查询传了数字 WHERE phone = 138,数据库给列加了隐式转换,等于对列用了函数。
  • LIKE 以通配符开头:WHERE name LIKE '%abc' —— 排了序也没用,因为前缀不确定。

一个实用原则

索引不是越多越好 —— 每个索引都会拖慢写入(每次增删改都要同步维护所有索引)。给高频查询条件建索引,而不是给每个字段都建。慢查询第一反应是 EXPLAIN 看执行计划,而不是盲目加索引。