MySQL 中的聚簇索引和非聚簇索引有什么区别?

MySQL 中的聚簇索引和非聚簇索引有什么区别?

1. 从不同存储引擎去考虑
  1. 在MySIAM存储引擎中,索引和数据是分开存储的,包括主键索引在内的所有索引都是“非聚簇”的,每个索引的叶子节点存储的是数据记录的物理地址(指针),而不是数据本身
  2. 而在InnoDB存储引擎中,InnoDB 的主键索引是聚簇索引,叶子节点直接包含完整数据记录
2. 从InnoDB内部去考虑
  1. 聚簇索引
    1. 索引叶子结点存储的是数据行,可以直接访问完整数据
    2. 每个表只能有一个聚簇索引,通常是主键索引,适合范围查询和排序
  2. 非聚簇索引
    1. 索引的叶子结点存储的是主键和对应的索引列,而不是完整数据,如需访问完整数据需要根据主键回表查询
    2. 一个表可以有多个非聚簇索引,适用于快速查找对应的列数据

注意,主键索引和聚簇索引的区别,他们并不相等!

  1. 主键优先
    • 如果表定义了PRIMARY KEY,则自动使用主键作为聚簇索引
  1. 无主键时的选择
    • 如果没有主键,InnoDB会选择第一个所有列都是NOT NULL的UNIQUE索引作为聚簇索引
    • 如果既没有主键也没有符合条件的UNIQUE索引,InnoDB会内部生成一个隐藏的6字节列(DB_ROW_ID)作为聚簇索引
<think>我们正在讨论MySQL中的索引非聚簇索引(也称为二级索引)的区别。需要详细解释它们的概念、区别以及使用场景。注意:MySQL的InnoDB引擎使用索引,而MyISAM引擎使用的是非聚簇索引(即索引数据分开)。这里主要讨论InnoDB引擎,因为它是MySQL的默认引擎。</think> ### MySQL索引非聚簇索引详解在MySQL中,索引结构主要分为**索引****非聚簇索引**(二级索引)。这两种索引在数据存储方式查询效率上有显著区别: #### 1. **索引(Clustered Index)** - **定义**:数据行的物理存储顺序与索引顺序一致的索引类型 - **特征**: - 表数据存储在索引的叶子节点上(索引即数据) - 每个表只能有一个索引(通常是主键) - 物理存储按索引值排序 ```sql -- InnoDB引擎自动为主键创建索引 CREATE TABLE employee ( id INT PRIMARY KEY, -- 自动成为索引 name VARCHAR(100) ); ``` **工作示意图**: ``` ┌───────────────┐ │ 索引节点 (id) │ ├───────────────┤ │ 指针/数据页 │ ← 数据直接存储在索引页 └───────────────┘ ``` #### 2. **非聚簇索引(Non-clustered Index)** - **定义**:索引顺序与数据物理存储顺序无关的索引 - **特征**: - 叶子节点存储的是主键值(而非实际数据) - 每个表可以有多个非聚簇索引 - 需要二次查找才能获取完整数据 ```sql -- 创建非聚簇索引(二级索引) CREATE INDEX idx_name ON employee(name); -- 二级索引 ``` **工作示意图**: ``` ┌───────────────┐ ┌───────────────┐ │ 索引节点 (name) │─────→│ 数据页 (主键id) │ ├───────────────┤ ├───────────────┤ │ 指针/主键值 │ │ 实际数据行 │ └───────────────┘ └───────────────┘ ``` ### 核心区别对比表 | **特性** | **索引** | **非聚簇索引** | |------------------------|------------------------------|----------------------------| | 数量限制 | 每表仅限1个 | 可创建多个 | | 存储内容 | 实际数据行 | 主键值 | | 是否需要二次查找 | 否(直接获取数据) | 是(需回表查询) | | 主键是否自动创建 | 是(InnoDB引擎) | 否(需手动创建) | | 数据更新代价 | 高(需重排整个数据页) | 低(仅更新索引页) | | 范围查询效率 | 高(连续存储) | 低(离散查找) | | 常见使用场景 | 主键、频繁范围查询的列 | WHERE条件列、JOIN关联列 | ### 查询过程差异示例**场景**:查询name为'John Doe'的员工记录 **使用索引(主键查询)**: ```sql SELECT * FROM employee WHERE id = 1001; ``` - 直接通过索引定位数据页,一次I/O获取完整数据 **使用非聚簇索引(普通索引查询)**: ```sql SELECT * FROM employee WHERE name = 'John Doe'; ``` 1. 通过name索引查找到对应的主键id 2. 通过主键id回到索引查找实际数据 3. 至少需要两次I/O操作(回表查询) ### 性能优化建议 1. **优先使用索引**:对于主查询条件,尽量使用主键或索引列 2. **索引覆盖优化**:使非聚簇索引包含查询所需字段 ```sql -- 添加覆盖索引避免回表 CREATE INDEX idx_covering ON employee(name, department); -- 查询可直接使用索引 SELECT name, department FROM employee WHERE name = 'John Doe'; ``` 3. **避免碎片化**:定期优化表减少索引碎片 ```sql OPTIMIZE TABLE employee; ``` 4. **联合索引设计**:多条件查询时创建复合索引 ```sql CREATE INDEX idx_dept_salary ON employee(department, salary); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值