聚簇索引、非聚簇索引、覆盖索引

聚簇索引、非聚簇索引、覆盖索引


本篇将带你搞懂什么是聚簇索引、非聚簇索引、覆盖索引,并且通过画图的方式了解索引查找的过程,明白什么是回表查询

索引(Index)是数据库中一种用于快速查找和访问表中数据的结构,它类似于书的目录,通过索引可以快速定位到目标数据,而无需遍历整个表,索引的存在可以显著提高查询速度,尤其是在处理大量数据时

MySQL中默认使用索引的数据结构是B+树,详细可以参考:MySQL索引为什么是B+数-优快云博客

那什么又是聚簇索引、非聚簇索引、覆盖索引?

聚簇索引

聚簇索引也叫聚集索引,是一种将数据行的物理存储顺序与索引的逻辑顺序相同的索引,换句话说,数据是直接存储在索引的叶子节点中,通过主键查找到某一行数据,这一行数据的全部内容都存放在这个叶子节点中,聚簇索引必须有,而且只能有一个

以下面这个表为例:

idnameusernameage
1001张三zhangsan20
1002李四lisi18
1003王九wangjiu35
1004赵六zhaoliu22
1005王八wangba17
1006李白libai40
1007杜甫dufu33

以主键id来为其生成一个简单的B+树索引为:

在这里插入图片描述

这个利用主键字段来生成的索引就是一个聚簇索引,当我们通过id查找某一个用户时,通过查找算法,找到了他所在的叶子节点,那么在这个叶子节点中,就存放了该用户的整行数据,包括姓名、账号、年龄:

在这里插入图片描述

如果定义了主键,MySQL会自动将主键列作为聚簇索引;如果没有主键,MySQL会选择一个唯一非空索引;如果没有唯一索引,MySQL会生成一个隐藏的rowid作为主键来生成聚簇索引


非聚簇索引

相比于聚簇索引,非聚簇索引也叫二级索引,它的叶子节点存储的是索引列的值以及指向实际数据行的指针(或主键值),而不是完整的数据行,也就是说,非聚簇索引的叶子节点中,存放的不再是整行数据,而是该行数据的主键

当我们为上表建立索引时,使用的不是id,而是username

在这里插入图片描述

默认会使用字母顺序来进行排序,但是其叶子节点中存储的不再是整行数据,而是该行数据的索引值

回表查询

回表查询是数据库查询中的一个术语,指的是在使用非聚簇索引(或普通索引)时,数据库查询引擎需要通过索引查找到对应的行号(或主键值),然后再回到表中查找完整的行数据的过程

以上表为例,我们想要查询usernamezhaoliu的用户全部信息:

select * from user where username = 'zhaoliu'

1.此时回先到username的非聚簇索引中去查找

通过username的比对查找,找到了zhaoliu所在的叶子节点,但是叶子节点中并没有我们需要的全部用户信息,只有该用户的主键值id

2.这时就会拿着id去聚簇索引中比对查找

找到该用户的叶子节点,再把叶子节点中的整行数据返回

在这里插入图片描述

回表查询增加了 I/O 操作,尤其是表数据量大时会显著降低性能,所以我们在设计索引时,尽量要避免出现回表查询

当查询的字段较少且频率较高时,建议使用覆盖索引优化查询


覆盖索引

覆盖索引(Covering Index) 是一种索引优化技术,指的是查询所需的所有字段都可以直接从索引中获取,无需再回表查询。这种方式可以显著提高查询性能,因为避免了回表操作

也就是说,当我们建立索引时,不再使用单一字段来建立索引,而是包含多个字段,这样在利用索引进行查询信息时,叶子节点中可以包含全部的所需数据,不必再到其他索引中查询,因此可以避免回表查询

比如之前以username建立的索引,如果我们不查询用户的全部数据,而是只需要返回usernameid

select id,name from user where name = 'zhangsan'

username建立的索引中已经包含了想要的全部数据:usernameid,因此不需要再去查询其他的索引,这就是覆盖索引

在建立索引时,可以设置多字段建立索引:

CREATE INDEX idx_name_age ON users(name, age)

这样索引的叶子节点中就存放了更多的数据

在这里插入图片描述

当我们查询所需要的信息nameage时,索引 idx_name_age 包含 nameage,因此查询所需的字段完全覆盖,无需回表

SELECT name, age FROM users WHERE name = 'John'

但是覆盖索引也有一些弊端

  1. 增加存储开销
    • 索引存储需要额外空间,字段越多,索引越大。
  2. 写性能受影响
    • 插入、更新、删除操作需要同时更新覆盖索引,导致写入开销增加。
  3. 适用场景有限
    • 覆盖索引适用于查询固定字段的场景,但无法应对动态字段需求。
<think>好的,我现在需要处理用户关于索引非聚簇索引的问题。用户已经提供了三个引用,我需要先仔细理解这些内容,然后结合自己的知识来组织回答。首先,引用[3]明确指出索引的数据存储和索引放在一起,找到索引就找到数据,而非聚簇索引则是分开存储,索引叶子节点指向数据行。这应该是核心区别。用户想了解两者的概念及区别,还有工作原理,所以需要从定义、结构、数据存储方式、查找过程等方面展开。 接下来,引用[1]和[2]提到了索引非聚簇索引在数据库优化中的应用,包括性能差异和适用场景。这说明在回答时还需要比较它们的优缺点,比如查询速度、插入性能、存储空间等,并给出实际应用中的建议,比如何时使用哪种索引。 我需要确保回答结构清晰,可能分为几个部分:定义对比、工作原理、优缺点、使用场景。同时,用户提到需要内联数学公式和独立公式的LaTeX格式,但在这个主题中数学公式可能较少,不过如果有涉及性能分析的公式,比如时间复杂度,可能需要用$O(n)$这样的表达。另外,用户之前的问题是关于Java异常的,现在转向数据库索引,需要确保回答专注于当前主题,不混淆之前的内容。引用中的例子可能涉及MySQL,所以回答中要明确数据库类型,但原理是通用的。需要检查是否有遗漏的点,比如索引一个表只能有一个,而非可以有多个,这点很重要。还有主键索引和辅助索引的关系,是否属于或非。引用[3]提到主键索引和辅助索引的分类,这可能要结合到回答中。最后,生成相关问题需要考虑用户可能深入的问题,比如索引的底层结构(B+树)、如何选择索引类型、具体优化案例等。确保问题与当前主题相关,并引导用户进一步学习。</think>### 索引非聚簇索引核心解析 --- #### 一、基本定义与核心区别 1. **索引 (Clustered Index)** - **存储特性**:数据行物理存储顺序与索引逻辑顺序一致,索引即数据文件 - **唯一性**:每个表只能有一个索引(通常为主键索引)[^3] - **查找过程**:$B+树 \rightarrow 直接定位数据页$,无需二次查找 2. **非聚簇索引 (Non-Clustered Index)** - **存储特性**:索引与数据分离存储,索引结构独立于数据文件 - **多索引支持**:一个表可创建多个非聚簇索引 - **查找过程**:$B+树 \rightarrow 行指针 \rightarrow 数据页$,需二次寻址[^3] $$ \text{索引类型差异矩阵} = \begin{cases} \text{数据存储方式} & \text{索引:数据与索引合并} \\ \text{索引数量} & \text{索引:1个/表;非聚簇索引:多个/表} \\ \text{查询效率} & \text{索引:范围查询快;非聚簇索引:单点查询快} \end{cases} $$ --- #### 二、工作原理深度解析 ##### 1. **索引工作机制** ```sql -- 创建示例(MySQL默认主键为索引) CREATE TABLE users ( id INT PRIMARY KEY, -- 索引 name VARCHAR(50), INDEX idx_name(name) -- 非聚簇索引 ); ``` - **物理存储结构**: - 数据页按主键顺序排列 - 叶子节点直接存储数据行 ##### 2. **非聚簇索引执行流程** ```sql SELECT * FROM users WHERE name = 'Alice'; -- 使用idx_name索引 ``` 1. 遍历`idx_name`索引树找到匹配记录 2. 获取对应的主键值 3. 回表查询索引获取完整数据行[^3] --- #### 三、性能对比与适用场景 | 对比维度 | 索引 | 非聚簇索引 | |------------------|-----------------------------------|-----------------------------------| | **范围查询** | 极快(数据物理连续)[^1] | 较慢(需多次跳转) | | **插入速度** | 慢(需维护物理顺序) | 快(仅更新索引) | | **存储空间** | 节省空间(无额外存储) | 消耗更多空间(独立索引结构) | | **典型场景** | 主键查询、ORDER BY排序[^2] | WHERE条件过滤、JOIN连接列 | --- #### 四、设计实践建议 1. **选择原则** - 频繁范围查询的列适合索引 - 高更新频率的列避免使用索引 2. **优化技巧** - **覆盖索引**:通过非聚簇索引直接获取数据,避免回表 ```sql CREATE INDEX idx_covering ON users(name, age); -- 包含查询所需字段 ``` - **索引合并**:对多个非聚簇索引使用`INDEX MERGE`优化 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值