一、聚簇索引与非聚簇索引
索引按照物理实现方式,索引可以分为2种:聚(聚集)和非聚簇(非聚集)索引。我们也把非聚集索引称为二级索引或者辅助索引。
聚簇索引:基于主键构建的索引或者b+tree。聚簇索引并不是一种单独的索引类型,而是一种数据存储方式(所有的用户记录都存储在了叶子节点),也就是所谓的 索引即数据,数据即索引。术语“聚簇"表示数据行和相邻的键值聚簇的存储在一起。
非聚簇索引:针对非主键构建的索引。
InnoDB 与聚簇索引(Clustered Index)有着深度绑定的关系—— 聚簇索引是 InnoDB 存储引擎的核心索引机制,也是其区别于 MyISAM 等其他引擎的关键特性之一。
二、核心关系:InnoDB 表必须有且仅有一个聚簇索引
在 InnoDB 中,数据行的物理存储顺序与聚簇索引的逻辑顺序完全一致,即数据行本身就存储在聚簇索引的叶子节点中。这种 “索引即数据,数据即索引” 的结构,是 InnoDB 聚簇索引的核心特点。
具体表现为:
聚簇索引是数据的物理组织方式
InnoDB 的表数据并不是随机存放在磁盘上的,而是按照聚簇索引的顺序依次排列。查询时通过聚簇索引可以直接定位到数据行,无需额外查找数据位置。默认使用主键作为聚簇索引
如果表定义了主键(
PRIMARY KEY
),InnoDB 会以主键作为聚簇索引。如果没有主键,InnoDB 会选择第一个唯一非空索引作为聚簇索引。
如果既没有主键也没有合适的唯一索引,InnoDB 会自动生成一个隐藏的 6 字节自增 row_id 作为聚簇索引。
三、聚簇索引与非聚簇索引(二级索引)的关联
InnoDB 中除聚簇索引外的其他索引(如普通索引、唯一索引)都称为二级索引,它们与聚簇索引的关系是:
二级索引的叶子节点不存储完整数据行,只存储聚簇索引的键值(即主键值)。
当通过二级索引查询时,需要先找到对应的聚簇索引键值,再通过聚簇索引定位到完整数据行(这个过程称为 “回表”)。
例:
假设表 user
以 id
为主键(聚簇索引),有一个二级索引 idx_name
(基于 name
字段):
聚簇索引的叶子节点存储
(id, name, age, ...)
完整数据行。二级索引
idx_name
的叶子节点存储(name, id)
,查询时需通过id
回表找完整数据。
四、为什么 InnoDB 依赖聚簇索引?
这种设计的核心目的是优化查询性能:
对于主键查询(如
WHERE id = 100
),可直接通过聚簇索引定位数据,效率极高。对于范围查询(如
WHERE id BETWEEN 100 AND 200
),由于数据按聚簇索引顺序存储,可快速读取连续的物理数据块,减少磁盘 IO。
五、与 MyISAM 的对比
MyISAM 采用非聚簇索引,其索引与数据完全分离:
索引的叶子节点存储数据行的物理地址(类似指针),而非数据本身。
主键索引与普通索引在结构上无区别,仅主键索引要求键值唯一。
因此,MyISAM 中不存在 “聚簇索引” 的概念,这也是 InnoDB 与 MyISAM 在索引机制上的核心差异之一。
六、聚簇索引数据存储特点
使用记录主键值的大小进行记录和页的排序,这包括三个方面的含义:
页内
的记录是按照主键的大小顺序排成一个单向链表
。各个存放
用户记录的页
也是根据页中用户记录的主键大小顺序排成一个双向链表
。存放
目录项记录的页
分为不同的层次,在同一层次中的页也是根据页中目录项记录的主键大小顺序排成一个双向链表
。
B+树的
叶子节点
存储的是完整的用户记录。所谓完整的用户记录,就是指这个记录中存储了所有列的值(包括隐藏列)。
我们把具有这两种特性的B+树称为 聚簇索引 ,所有完整的用户记录都存放在这个 聚簇索引的叶子节点处。这种聚簇索引并不需要我们在MySQL语句中显式的使用 INDEX语句去创建, InnoDe 存储引擎会自动 的为我们创建聚簇索。
优点:
-
数据访问更快
,因为聚簇索引将索引和数据保存在同一个B+树中,因此从聚簇索引中获取数据比非聚簇索引更快- 聚簇索引对于主键
排序查找范围查找
速度非常快- 按照聚簇索引排列顺序,查询显示一定范围数据的时候,由于数据都是紧密相连,数据库不用从多个数据块中提取数据,所
节省了大量的io操作
。缺点:
-
插入速度严重依赖于插入顺序
,按照主键的顺序插入是最快的方式,否则将会出现页分裂,严重影响性能。因此,对于InnoDB表,我们一般都会定义一个**自增ID列为主键**-
更新主键的代价很高
,因为将会导致被更新的行移动。因此,对于InnoDB表,我们一般定义**主键为不可更新**-
二级索引访问需要两次索引查找
,第一次找到主键值,第二次根据主键值找到行数据
七、总结
聚簇索引是 InnoDB 表的物理存储方式,数据与索引融为一体。
InnoDB 必须依赖聚簇索引组织数据,而聚簇索引通常由主键承担。
这种设计使 InnoDB 在主键查询和范围查询上性能优异,但也导致二级索引查询需要 “回表”,这是使用时需要注意的点(可通过 “覆盖索引” 优化)。
在 InnoDB 中,只有与主键相关的索引才可能是聚簇索引。如果索引不是基于主键构建的(即二级索引,如普通索引、唯一索引等),那么它一定不是聚簇索引。
聚簇索引的唯一性
InnoDB 表有且仅有一个聚簇索引,且其必然与 “主键” 绑定:若表定义了主键(PRIMARY KEY),则聚簇索引就是主键索引。
若未定义主键,InnoDB 会选择第一个非空唯一索引作为聚簇索引。
若既无主键也无合适的唯一索引,InnoDB 会自动生成一个隐藏的 row_id 作为聚簇索引(用户不可见)。
因此,聚簇索引的本质是 “组织数据物理存储顺序的索引”,且必然与表的 “主键标识” 绑定,不可能是普通的非主键索引。
非主键索引(二级索引)的本质
所有不基于主键的索引(如 KEY idx_name (name))都属于二级索引,其结构与聚簇索引有本质区别:聚簇索引的叶子节点存储完整的数据行(数据与索引融合)。
二级索引的叶子节点只存储该索引的键值 + 聚簇索引的键值(即主键值),不存储完整数据。
例如,表 user 有主键 id(聚簇索引)和二级索引 idx_age(基于 age):
聚簇索引(id)的叶子节点:(id, name, age, ...)(完整数据)。
二级索引(age)的叶子节点:(age, id)(仅索引键 + 主键值)。
当通过二级索引查询时,需要先找到对应的主键值,再通过聚簇索引查询完整数据(称为 “回表”)。
在 InnoDB 中:
只有与主键(或 InnoDB 自动生成的 row_id)相关的索引才是聚簇索引。
所有非主键索引都是二级索引,不可能是聚簇索引。
聚簇索引的核心是 “数据的物理存储顺序与索引逻辑顺序一致”,这一特性仅与表的主键绑定,与其他索引无关。