MySQL作为常用的关系型数据库,索引是提升查询效率的核心组件,不同类型的索引有着不同的实现逻辑和适用场景,其中聚簇索引、非聚簇索引、联合索引和唯一索引是最常接触的几类索引。

聚簇索引
聚簇索引并不是单独的索引类型,而是一种数据存储方式。InnoDB引擎的聚簇索引会将数据行和索引键存储在一起,索引的叶子节点直接保存了整行数据,也就是说数据表的物理存储顺序和聚簇索引的排序顺序是一致的。
每个InnoDB表有且只有一个聚簇索引,默认会选择主键作为聚簇索引,如果表没有定义主键,会选择一个唯一非空索引代替,如果也没有这样的索引,InnoDB会隐式创建一个隐藏的聚簇索引。
聚簇索引的优势是查询覆盖索引时可以直接获取整行数据,不需要回表,查询速度更快;缺点是插入新数据时如果主键不是自增的,可能会导致页分裂,影响插入性能。
聚簇索引示例
创建一张用户表,设置id为主键,此时id列就是聚簇索引:
-- 创建用户表,id为主键,默认作为聚簇索引
CREATE TABLE user (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL,
age INT NOT NULL
) ENGINE=InnoDB;
-- 插入测试数据
INSERT INTO user (name, age) VALUES ('张三', 20), ('李四', 25), ('王五', 22);
非聚簇索引
非聚簇索引也称为二级索引,它的叶子节点不存储整行数据,而是存储聚簇索引的键值。当通过非聚簇索引查询数据时,首先需要找到对应的聚簇索引键值,然后再通过聚簇索引查询到整行数据,这个过程称为回表。
除了聚簇索引之外的其他索引都是非聚簇索引,比如我们给普通列创建的索引、唯一索引、联合索引本质上都属于非聚簇索引。
非聚簇索引示例
给user表的name列创建普通索引,这个索引就是非聚簇索引:
-- 给name列创建普通索引(非聚簇索引) CREATE INDEX idx_user_name ON user(name); -- 查询name为张三的记录,会先通过idx_user_name找到对应的id,再回表查整行数据 SELECT * FROM user WHERE name = '张三';
联合索引
联合索引是指同时包含两个或两个以上列的索引,索引的排序规则是先按照第一个列排序,第一个列值相同的情况下再按照第二个列排序,以此类推,这就是最左前缀原则的来源。
联合索引的优势是可以用一个索引覆盖多个查询条件,减少索引的创建数量,节省存储空间。需要注意的是,如果查询条件没有使用联合索引的最左列,索引可能无法生效。
联合索引示例
给user表创建name和age的联合索引:
-- 创建name和age的联合索引 CREATE INDEX idx_user_name_age ON user(name, age); -- 以下查询可以使用联合索引 SELECT * FROM user WHERE name = '张三' AND age = 20; -- 以下查询也可以使用联合索引(最左前缀) SELECT * FROM user WHERE name = '张三'; -- 以下查询无法使用联合索引,因为缺少最左列name SELECT * FROM user WHERE age = 20;
唯一索引
唯一索引是一种约束性索引,它要求索引列的值必须唯一,允许为空,但空值可以出现多次。唯一索引可以是单列索引,也可以是联合索引,如果是联合唯一索引,则要求多个列的组合值唯一。
唯一索引的主要作用除了提升查询效率之外,还能保证业务数据的唯一性,比如用户表的手机号、邮箱列通常会创建唯一索引,避免重复数据。
唯一索引示例
给user表新增email列,并创建唯一索引:
-- 新增email列
ALTER TABLE user ADD COLUMN email VARCHAR(100);
-- 创建email的唯一索引
CREATE UNIQUE INDEX idx_user_email ON user(email);
-- 插入重复email会报错
INSERT INTO user (name, age, email) VALUES ('赵六', 30, 'test@ipipp.com');
-- 再次插入相同email会失败
INSERT INTO user (name, age, email) VALUES ('孙七', 31, 'test@ipipp.com');
四类索引的核心区别
四类索引的核心差异可以通过以下表格对比:
| 索引类型 | 存储内容 | 数量限制 | 核心作用 |
|---|---|---|---|
| 聚簇索引 | 叶子节点存储整行数据 | 每个表仅1个 | 决定数据物理存储顺序,提升主键查询效率 |
| 非聚簇索引 | 叶子节点存储聚簇索引键值 | 无限制 | 提升非主键列的查询效率,需要回表 |
| 联合索引 | 多列组合排序,叶子节点存储聚簇索引键值 | 无限制 | 覆盖多列查询条件,遵循最左前缀原则 |
| 唯一索引 | 普通索引结构,额外约束列值唯一 | 无限制 | 提升查询效率,同时保证数据唯一性 |
使用建议
- 优先使用自增主键作为聚簇索引,减少页分裂问题,提升插入性能。
- 非聚簇索引不要创建过多,因为每个非聚簇索引都会占用额外存储空间,且会影响写入性能。
- 联合索引的列顺序要符合查询频率,最常用作查询条件的列放在最左边。
- 需要保证唯一性的列优先创建唯一索引,既满足约束又提升查询效率。