文章背景图

MySQL 索引笔记:从 B+ 树说起

为什么不是二叉树

数据在磁盘上,一次 IO 读一页(InnoDB 默认 16KB)。二叉树的层数等于树的深度,一千万条数据树高 24 层,就是 24 次磁盘 IO。

B+ 树把"一个节点存一个值"改成"一个节点存一页的值"。一页 16KB,每条索引记录大约十几字节,一页能放上千个 key,三到四层就能撑起上亿数据。

索引结构的选择,本质上是在减少磁盘 IO 次数。

为什么不是哈希

哈希索引等值查询是 O(1),但:

  • 不支持范围查询,where create_time > '2026-01-01' 用不上
  • 不支持排序,还得额外排一次
  • 不支持最左前缀

InnoDB 的自适应哈希索引是个例外——它是引擎自己加的,不用手动建。

聚簇索引和二级索引

InnoDB 的表本身就是按主键组织的 B+ 树,叶子节点存的是整行数据,这叫聚簇索引。

二级索引的叶子节点存的是主键值。所以:

select * from article where title = 'xxx';

先在 title 索引上找到主键,再拿主键回聚簇索引查整行,这就是"回表"。

如果只需要 id:

select id from article where title = 'xxx';

索引里就有,不用回表,叫覆盖索引。这也是为什么 select * 是个坏习惯。

最左前缀

建了 (a, b, c) 联合索引,相当于建了 (a)、(a, b)、(a, b, c) 三个索引。

-- 能用
where a = 1
where a = 1 and b = 2
where a = 1 and b = 2 and c = 3
where a = 1 and c = 3          -- 只用到 a

-- 不能用
where b = 2
where c = 3

where a = 1 and c = 3 里,c 用不上索引,因为 b 断了。范围查询之后的条件也失效:

where a = 1 and b > 2 and c = 3   -- c 用不上

什么时候索引会失效

  • 在索引列上做运算:where id + 1 = 10
  • 隐式类型转换:varchar 列写成 where phone = 13800000000(少了引号)
  • 前导模糊:like '%张三'
  • or 连接了没有索引的列

怎么确认

explain select * from article where title = 'xxx';

重点看 type(ref 比 range 好,all 是全表扫描)、key(实际用了哪个索引)、rows(预估扫描行数)、Extra(出现 Using filesort、Using temporary 就要注意了)。

一句话总结

索引不是越多越好:每个索引都是一棵额外的 B+ 树,写入时要同步维护。高频查询、区分度高、能覆盖常用字段的,才值得建。

  • 作者:一颗星
  • 发表时间:2026-04-20
  • 标签:MySQL、索引、数据库
  • 版权声明:署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0),转载请注明出处
  • 站点性质:本站为个人非经营性网站,不接受任何形式的打赏与赞助