SQL 的索引是一种与表或视图关联、用于加速数据检索的磁盘结构。它按一列或多列建立键值,并以 B 树(行存储实际实现为 B+ 树)等有序结构组织,让数据库不必全表扫描就能快速定位目标行。据 Microsoft Learn 的官方定义,索引是”与表或视图关联、可加快从中检索行的磁盘结构”,索引键存储在 B 树中,使引擎能高效找到对应行。创建 PRIMARY KEY 或 UNIQUE 约束时,SQL Server 等引擎会自动建立相应索引。索引的本质是”空间换时间”——它占用额外存储并在写入时增加维护成本,但能大幅减少磁盘 IO。
一、索引在解决什么问题
没有索引时,查询只能做全表扫描:逐行读取整张表,挑出满足条件的行。据 Microsoft Learn 的查询优化说明,全表扫描会产生大量磁盘 IO,资源消耗高;一旦存在可用索引,优化器会在索引键列中查找,再定位数据行,通常远快于扫表。索引类似书籍目录——先查目录页找到页码,再翻到正文,而不是一页页翻。
二、索引的底层结构
索引的存储结构决定了它能做什么。主流结构有三种:
| 结构 | 工作原理 | 支持的能力 | 典型使用 |
|---|---|---|---|
| B 树 / B+ 树 | 多叉有序树,键值排序存放 | 等值、范围、排序、前缀匹配 | 绝大多数通用索引(InnoDB 默认 B+ 树) |
| 哈希索引 | 哈希表映射键到行 | 仅等值查询,极快 | 内存表、精确匹配 |
| 列存储索引 | 按列而非按行存储 | 海量数据分析、压缩率高 | 数据仓库只读负载 |
据腾讯云开发者社区与 CSDN 的整理,MySQL InnoDB 的默认结构是 B+ 树:非叶子节点只存键、叶子节点存数据并通过链表相连,因此特别适合范围查询。哈希索引不支持范围查询和排序,只做精确匹配。
三、按物理存储:聚集与非聚集
这是最关键的二分法(综合 Microsoft Learn 与多个 MySQL 教程):
聚集索引(Clustered):数据行的物理存储顺序与索引键顺序一致,索引的叶子节点直接保存完整数据行。一张表只能有一个聚集索引,因为数据行本身只能按一种顺序存放。在 InnoDB 中,主键即聚集索引;若无主键,则选第一个唯一非空索引;再无则隐式生成。
非聚集索引(Non-clustered):索引与数据分开存储,叶子节点保存索引键值和行定位符(指向聚集索引键或堆中的行)。一张表可有多个非聚集索引。查询走非聚集索引后,往往还要用定位符”回表”取完整数据,比聚集索引多一次查找。
两者对比:
| 对比维度 | 聚集索引 | 非聚集索引 |
|---|---|---|
| 数据存储 | 叶子节点即数据本身 | 叶子节点存键 + 定位符 |
| 每表数量 | 最多 1 个 | 可有多个 |
| 查询路径 | 直接定位数据 | 需回表再取数据 |
| 写入影响 | 较大(可能重排) | 较小 |
四、按功能与约束:唯一、主键、普通、全文
据 cnblogs 与 runnerliu 博客的分类:
- 主键索引:特殊的唯一索引,不允许 NULL,一张表只能有一个,建表时指定或自动创建。InnoDB 中它同时是聚集索引。
- 唯一索引(Unique):索引列值必须唯一,但允许单个 NULL。据 Microsoft Learn,唯一性既可以是聚集索引的属性,也可以是非聚集索引的属性。
- 普通索引(Normal):最基础的索引,无唯一约束,一个表可有多个单列索引。
- 全文索引(Full-text):基于词元的特殊功能索引,由全文引擎维护,用于字符串中的复杂词语搜索。
- 空间索引(Spatial):针对几何数据类型,加速空间对象运算。
- 复合索引(组合 / 联合索引):在多个列上建立,遵循最左前缀原则(详见 13138 篇)。
五、特殊类型:筛选、包含列、列存储
Microsoft Learn 还列出几种进阶索引:
- 筛选索引(Filtered):只索引表中满足过滤谓词的子集,比全表索引更小、维护更轻,适合固定子集查询。
- 包含列索引(带 INCLUDE):非聚集索引扩展出非键列,使索引本身就能覆盖查询、避免回表。
- 列存储索引(Columnstore):面向列存储与列处理,数据仓库负载下可达传统行存储约 10 倍查询性能提升与约 7 倍压缩率。
六、创建与删除语法
-- 普通索引
CREATE INDEX idx_name ON users(name);
-- 唯一索引
CREATE UNIQUE INDEX idx_email ON users(email);
-- 复合索引
CREATE INDEX idx_status_time ON orders(status, create_time);
-- 删除索引
DROP INDEX idx_name ON users;
据 CSDN 的语法示例,PRIMARY KEY 在建表时指定会自动建聚集索引;UNIQUE 约束自动建非聚集唯一索引。
七、索引的两面性
索引不是越多越好。据 cnblogs 的优缺点分析:
- 优点:加快
WHERE等值/范围查询、加速ORDER BY与GROUP BY、提升JOIN性能、唯一索引保证数据唯一。 - 缺点:占用额外磁盘/内存空间;
INSERT/UPDATE/DELETE需同步维护索引,拖慢写入;增加维护成本。
经验上,高频查询列、高选择性列、外键列优先建索引;写多读少、低基数列(如性别)则谨慎。
常见问题(FAQ)
一张表能有几个聚集索引?
最多 1 个。数据行物理顺序只有一种,InnoDB 中主键即为聚集索引。
唯一索引和主键索引有何不同?
主键索引不允许 NULL 且每表唯一一个;唯一索引允许单个 NULL,可建多个,两者都可聚集或非聚集。
哈希索引为什么不适合范围查询?
哈希表只做键到行的等值映射,不支持键的顺序遍历,因此范围、排序类查询用不了。