深入理解聚簇索引与非聚簇索引

145 阅读3分钟

深入理解聚簇索引与非聚簇索引

最通俗易懂的区别解释

想象一本书:

  • 聚簇索引:就像书的目录,目录顺序和实际页码顺序完全一致(如按章节顺序排列)
  • 非聚簇索引:就像书后的术语索引,术语按字母排序,但指向的页码是乱序的

核心区别详解

1. 数据存储方式

  • 聚簇索引:数据行实际存储在索引的叶子节点中(数据即索引)

    • 类似于字典本身是按字母顺序排列的
  • 非聚簇索引:叶子节点只存储指向数据的"指针"(主键值或行地址)

    • 类似于书后的索引只告诉你术语在哪些页码

2. 创建方式对比

MySQL InnoDB引擎创建聚簇索引
-- 方法1:创建主键(自动成为聚簇索引)
CREATE TABLE students (
    id INT PRIMARY KEY,  -- 这自动成为聚簇索引
    name VARCHAR(50),
    age INT
);

-- 方法2:如果没有主键,InnoDB会自动选择唯一非空列,或生成隐藏的row_id作为聚簇索引
创建非聚簇索引
-- 在已有表上创建非聚簇索引
CREATE INDEX idx_name ON students(name);

-- 创建复合非聚簇索引
CREATE INDEX idx_name_age ON students(name, age);

3. 查询过程差异

聚簇索引查询(查找id=5的学生):

  1. 直接定位到索引中的id=5节点
  2. 该节点就包含完整的学生数据(id,name,age)

非聚簇索引查询(按name查找):

  1. 先查name索引,找到对应的id值
  2. 再用这个id值去聚簇索引中查找完整记录(这就是回表)

如何选择创建聚簇索引

最佳实践原则

  1. 优先使用自增主键:INT/BIGINT AUTO_INCREMENT最佳

    CREATE TABLE users (
        user_id INT AUTO_INCREMENT PRIMARY KEY,  -- 理想聚簇索引
        username VARCHAR(50),
        email VARCHAR(100)
    );
    
  2. 避免使用频繁更新的列:因为每次更新都会导致数据物理位置变化

  3. 考虑查询模式:最常用的等值查询或范围查询列适合作为聚簇索引

特殊情况处理

需要修改聚簇索引的情况(MySQL InnoDB):

-- 必须先删除原主键(会重建表,谨慎操作)
ALTER TABLE students DROP PRIMARY KEY;

-- 然后添加新的主键
ALTER TABLE students ADD PRIMARY KEY (new_column);

性能对比示例

假设有100万条订单数据:

-- 使用聚簇索引查询(主键id)
SELECT * FROM orders WHERE id = 123456;  -- 一次索引查找即可

-- 使用非聚簇索引查询(customer_id字段)
SELECT * FROM orders WHERE customer_id = 789; 
-- 1. 先查customer_id索引找到所有匹配的id
-- 2. 对每个id回表查询完整数据

总结选择策略

  1. 聚簇索引选什么:自增ID、不常更新、长度短的列
  2. 非聚簇索引建多少:根据查询需求创建,但不宜过多(影响写入性能)
  3. 重要原则:让最频繁的查询尽可能使用聚簇索引或覆盖索引

关键区别对比

特性聚簇索引非聚集索引
数量限制每表只能有一个每表可以有多个
数据存储方式索引叶子节点存储完整数据行叶子节点存储指向数据的指针
查询效率通常更高(一次检索)通常较低(可能需回表)
物理顺序决定数据物理存储顺序不影响数据物理存储顺序
自动创建主键自动创建(InnoDB)需要显式创建
更新代价较高(可能需重组数据)相对较低