MySQL 中的 聚簇索引(Clustered Index) 和 非聚簇索引(Non-Clustered Index) 是两种不同的索引存储结构,它们在数据组织和查询性能上有显著差异。以下是两者的核心区别和特点:
1. 聚簇索引(Clustered Index)
-
定义
聚簇索引的叶子节点直接存储表的实际数据行,索引的顺序决定了数据行的物理存储顺序。
每个表只能有一个聚簇索引(因为数据行无法按多种顺序物理存储)。 -
特点
- 存储结构:索引的叶子节点即数据页,数据行按索引键的顺序物理排列。
- 默认行为:在 InnoDB 引擎中,如果表定义了主键(PRIMARY KEY),则主键自动成为聚簇索引;若无主键,则选择第一个唯一非空索引(UNIQUE NOT NULL);若两者均无,InnoDB 会隐式生成一个隐藏的
ROWID作为聚簇索引。 - 查询效率:通过聚簇索引查找数据时,只需一次索引扫描即可直接获取数据,性能高。
- 插入性能:数据插入可能导致页分裂(Page Split),尤其是主键非单调递增时。
-
示例
假设表users的主键是id,则id是聚簇索引,数据按id顺序物理存储:id (PK) name age 1 Alice 25 2 Bob 30 3 Carol 28 物理存储顺序与
id顺序一致。
2. 非聚簇索引(Non-Clustered Index)
-
定义
非聚簇索引的叶子节点不存储实际数据行,而是存储指向数据行的指针(InnoDB 中为主键值,MyISAM 中为数据文件偏移量)。
一个表可以有多个非聚簇索引。 -
特点
- 存储结构:索引的叶子节点包含索引键值和指向数据行的指针(主键或物理地址)。
- 查询流程:通过非聚簇索引查询时,需先查索引找到主键,再通过主键回表(回到聚簇索引)查找完整数据行,称为 回表查询。
- 适用场景:适合覆盖索引(Covering Index)查询,避免回表。
- 存储引擎:InnoDB 和 MyISAM 均支持非聚簇索引,但实现方式不同:
- InnoDB:非聚簇索引叶子节点存储主键值。
- MyISAM:非聚簇索引叶子节点存储数据文件的物理地址。
-
示例
在users表上对name字段创建非聚簇索引:CREATE INDEX idx_name ON users(name);索引结构可能如下(假设主键为
id):name | id (主键) ------------- Alice | 1 Bob | 2 Carol | 3查询
name='Bob'时,需先通过idx_name找到id=2,再通过聚簇索引查找id=2的行。
3. 核心区别
| 特性 | 聚簇索引 | 非聚簇索引 |
|---|---|---|
| 存储数据 | 叶子节点存储数据行 | 叶子节点存储指向数据行的指针(主键或地址) |
| 索引数量 | 每个表仅一个 | 每个表可以有多个 |
| 查询效率 | 直接获取数据,无需回表 | 可能需要回表查询 |
| 插入性能 | 主键非递增时可能页分裂 | 不影响数据物理顺序 |
| 依赖关系 | 数据行的物理顺序由索引决定 | 独立于数据行的物理存储 |
4. 使用建议
-
优先选择聚簇索引:
- 主键尽量使用单调递增的字段(如自增 ID),避免页分裂。
- 高频查询的列可以考虑聚簇索引(如范围查询、排序)。
-
优化非聚簇索引:
- 使用覆盖索引(索引包含查询所需的所有字段),避免回表。
- 避免在非聚簇索引中使用过长的字段(如
VARCHAR(255)),增加存储和查询开销。
-
引擎选择:
- InnoDB 默认使用聚簇索引,适合事务和高并发场景;
- MyISAM 仅支持非聚簇索引,适合读密集型场景。
5. 示例对比
-- InnoDB 表(聚簇索引)
CREATE TABLE users (
id INT PRIMARY KEY, -- 聚簇索引
name VARCHAR(50),
age INT,
INDEX idx_name (name) -- 非聚簇索引(叶子节点存储主键 id)
);
-- MyISAM 表(非聚簇索引)
CREATE TABLE users_myisam (
id INT PRIMARY KEY, -- 非聚簇索引(存储文件偏移量)
name VARCHAR(50),
age INT
) ENGINE=MyISAM;
理解聚簇索引和非聚簇索引的差异,可以帮助优化数据库设计、索引策略和查询性能。
6306

被折叠的 条评论
为什么被折叠?



