跳到主要内容

数据库索引总览

索引是数据库用额外存储换查找与排序速度的结构。没有索引时,引擎往往只能扫描大量行;有合适索引时,可以快速定位到少量候选行,再读出真正需要的数据。

在 InnoDB 中,索引几乎总是 B+ 树(少数场景另有哈希、全文等)。理解索引 = 理解「B+ 树如何组织行」+「查询条件如何落到树的范围扫描」。

底层结构细节见:B 树与 B+ 树。


1. 没有索引会发生什么​

表 users 有 1000 万行,查询:

SELECT * FROM users WHERE email = 'a@example.com';
  • 无索引:引擎从第一行扫到最后一行(或扫完整段),最坏比较约 (O(n)) 次。
  • 有 email 上的 B+ 树索引:沿树下降到叶子,在有序叶子链表上定位等值或范围,I/O 与比较次数接近树高 + 匹配行数,通常远小于全表。

索引不是免费的:

  • 占用磁盘与缓冲池内存
  • 每次 INSERT / UPDATE / DELETE 可能维护多棵树
  • 过多、重复、无用的索引会拖慢写入并浪费空间

设计原则:为真正高频、选择性好、能缩小扫描范围的条件建索引,而不是「每列都建一个」。


2. InnoDB 的两类核心索引​

2.1 聚簇索引(Clustered Index)​

  • InnoDB 表数据本身就按主键(或隐藏 row id)组织在一棵 B+ 树里。
  • 叶子节点存完整行记录。
  • 一张表只有一棵聚簇索引树。
  • 主键查询通常最快:叶子即数据,无需再找别的树。

2.2 二级索引(Secondary Index / 非聚簇索引)​

  • 叶子节点存的是:索引列的值 + 主键值(不是完整行)。
  • 若查询还需要索引列之外的字段,需要拿主键再回聚簇索引查一次,称为 回表(table lookup)。
  • 若查询所需列都已在二级索引叶子中(含主键),可以 覆盖索引(covering index),避免回表。
二级索引叶子: [ email | primary_key ]
|
v 回表
聚簇索引叶子: [ pk | name | email | ... 整行 ]

以 users(id, name, email, age) 为例,可把 InnoDB 结构理解为:

表: users
列: id(PK), name, email, age

========================
1) 聚簇索引(PRIMARY, 按 id)
========================
叶子节点(整行):
[ id=1, name=Tom, email=tom@x.com, age=20 ]
[ id=2, name=Lucy, email=lucy@x.com, age=18 ]
[ id=3, name=Jack, email=jack@x.com, age=25 ]

========================
2) 二级索引(idx_email, 按 email)
========================
叶子节点(索引列 + 主键):
[ email=jack@x.com, pk=3 ]
[ email=lucy@x.com, pk=2 ]
[ email=tom@x.com, pk=1 ]

3. 回表 vs 覆盖索引​

-- 可能回表:索引只有 email,还要 name
SELECT name FROM users WHERE email = 'a@example.com';

-- 覆盖:联合索引 (email, name) 时,叶子已有 name + pk
SELECT name FROM users WHERE email = 'a@example.com';

经验:

  • SELECT * 很容易逼出回表;按需列更易覆盖。
  • 联合索引可以把「过滤列 + 高频投影列」排在一起,兼顾过滤与覆盖。
  • 回表次数多时,优化器甚至可能放弃二级索引改走全表(成本模型权衡)。

4. 索引与查询形态的对应关系​

查询形态索引是否友好说明
等值 = / IN友好点查或少量分支
范围 >, <, BETWEEN, LIKE 'ab%'友好叶子有序范围扫描
排序 ORDER BY 与索引顺序一致友好可能避免 filesort
前缀模糊 LIKE '%ab'不友好无法用 B+ 树从左定位
对索引列做函数/运算通常失效见索引优化

5. 本目录接下来读什么​

  1. 索引类型:主键、唯一、联合、前缀、全文等各自适用场景。
  2. 索引优化:最左前缀、常见失效、用 EXPLAIN 验证。

读完索引后,建议接上 事务基础:写入路径上的锁与 MVCC 都挂在这些索引结构上。