非聚簇索引叶子节点存储索引列值和主键值,不存整行数据;查询非索引字段需回表;支持覆盖索引避免回表;InnoDB存主键值因数据按主键聚簇,MyISAM存物理地址。

非聚簇索引(也叫二级索引、辅助索引)是 MySQL 中一种将索引与数据物理存储分离的索引结构。它不改变表中数据的实际存放顺序,叶子节点不存完整行记录,而是只存索引列值 + 对应主键值。
非聚簇索引的核心特点
在 InnoDB 引擎中:
- 每个非聚簇索引的 B+ 树叶子节点,存储的是「索引字段值」和「该行对应的主键值」,不是整行数据;
- 查询时若需要非索引字段(比如
SELECT name FROM user WHERE email = 'a@b.com'),必须先通过 email 索引找到主键 id,再用这个 id 回到聚簇索引树中查出 name —— 这个过程叫「回表」; - 一个表可以有多个非聚簇索引,数量上限为 249 个(MySQL 8.0+);
- 它不占用数据页空间,但会额外消耗磁盘和内存,且每次 INSERT/UPDATE/DELETE 都需同步更新所有相关非聚簇索引。
为什么非聚簇索引要存主键而不是行地址?
InnoDB 的设计决定:数据按主键顺序物理组织(聚簇索引),行位置可能随插入、删除、页分裂而变动。直接存行地址不可靠,而主键稳定唯一,能长期准确指向目标记录。
例如建表:
CREATE TABLE user (id INT PRIMARY KEY, name VARCHAR(32), email VARCHAR(64));再为 email 建索引:CREATE INDEX idx_email ON user(email);
此时 idx_email 就是非聚簇索引,其叶子节点内容类似:
[email='a@b.com'] → 主键 id=1024
后续查 SELECT * FROM user WHERE email = 'a@b.com' 就得走两次 B+ 树查找。
哪些情况能避免回表?
当查询语句所需的全部字段,都包含在非聚簇索引中时,就无需回表 —— 这叫「覆盖索引」。
-
SELECT email FROM user WHERE email = 'a@b.com'→ 只查索引字段,直接返回; -
SELECT email, id FROM user WHERE email = 'a@b.com'→ id 是主键,已在索引叶子中,仍属覆盖; - 但
SELECT email, name FROM user WHERE email = 'a@b.com'→ name 不在索引里,必须回表。
MyISAM 和 InnoDB 的非聚簇索引差异
MyISAM 的非聚簇索引叶子节点存的是「行的物理地址(即 .MYD 文件中的偏移量)」,而 InnoDB 存的是「主键值」。这是引擎底层设计的根本区别:MyISAM 数据文件本身无序,InnoDB 数据强制按主键有序。
因此,在 InnoDB 中,主键选择很重要 —— 主键越短(如 INT 而非 UUID),非聚簇索引占用空间就越小,性能损耗也越低。










