SQL中主键,聚集索引,非聚集索引的区别

本文详细解释了数据库中主键的概念及其作用,并探讨了聚集索引与非聚集索引的区别,以及它们如何影响数据存储和查询效率。

主键:

主键是表中通常有唯一标志着表中的每一行的值的一列或者多列,它的值用于唯一地标识表中的某一条记录,用于强制表的实体完整性。主键用来一个表引用来自其他表的特定记录,主键是一种唯一关键字,表定义的一部分。可以理解为一个记录行的标识。我们通过这个标识,就能精确把这行记录找出来,它在表中是唯一的

聚集索引:
前提是上面,如果我们定义了主键,那么innodb会选择主键作为聚集索引,如果没有显示定义的主键,那么就会选择不包含NULL值的唯一索引作为聚集索引,如果也没有这样的唯一索引列,那么INNODB就选着内置6字节长的rowID作为隐含的聚集索引,这里的RowId会随着记录的写入而主键自增,但是它是不可引用和查看的,是数据库引擎内部的使用。

如果我们使用自增主键,那么每次插入的新纪录都在原先记录的尾部按照顺讯的添加到当前节点的索引后面,当一页快写满的时候,就会开辟一个新的页。

数据记录本身就存与主索引的叶子节点上,B+tree的树。这就要求每一个叶子节点内的各条数据记录按主键顺序存放,因此每当有有一条新的记录插入的时候,MYSQL会根据其主键将其插入到合适的节点和位置上,如果页面达到装载因子(INNODB默认为15/16),则开辟新的页面(节点)

非聚集索引:

如果我们使用非聚集索引,例如我们平时所说的身份证号,学号等,因为每个人的身份证号,学号都不一样,所以我们每次插入的值等同随机插入,当插入一个新的数据的时候,MYSQL不得不给数据找一个合适的位置插入,并且可能会移动其他的数据记录位置,甚至目标页面可能已经被回写到磁盘上而从缓存中清掉了,此时又要从磁盘中读回来,这就增加了很多的开销,同时频繁的移动数据,分页操作造成数据的大量碎片。索引结构就不够紧凑,后续可能不得不Optimize table来重新构建表,进行优化。

总结:在效率方面最好使用聚集索引,并给表设定唯一主键。在数据索引的存储有序的情况下,可以大大提高效率。在有序的情况下,通过索引查询数据就无需遍历索引记录。就算在极端的情况下,数据查询的效率是二分法查询。将近是Log(N)

<think>我们正在回答用户的问题:SQL Server中聚集索引非聚集索引区别 根据引用内容,我们可以总结出以下关键点: 1. 数量限制:每个表只能有一个聚集索引,但可以有多个非聚集索引(引用[1][3][4])。 2. 数据存储:聚集索引决定数据的物理存储顺序,索引的叶节点就是数据行本身(引用[1][3])。而非聚集索引是逻辑排序,其叶节点包含索引键值指向实际数据行的指针(引用[1][2])。 3. 存储空间:聚集索引不占用额外的存储空间(因为它就是数据本身的存储方式),而非聚集索引需要额外的存储空间(引用[4][5])。 4. 性能:聚集索引通常更快,因为通过聚集索引查找数据可以直接获取数据行,而非聚集索引需要额外的查找步骤(即键查找)来定位实际数据行(引用[1][4][5])。 5. 主键默认:在SQL Server中,创建表时主键默认是聚集索引(引用[3])。 6. 维护开销:聚集索引对插入更新操作的开销更大,因为数据需要按索引顺序存储(引用[1])。 接下来,我们将这些关键点整理成结构化的回答,并在适当位置添加引用标记。</think>### SQL Server 聚集索引非聚集索引区别 #### 1. **数量限制** [^1][^3][^4] - **聚集索引**:每个表**只能有一个**,因为数据行只能按一种物理顺序存储。 ```sql -- 创建主键时自动生成聚集索引(默认行为) ALTER TABLE Orders ADD PRIMARY KEY (OrderID); ``` - **非聚集索引**:每个表**可以有多个**(最多999个),支持不同字段的查询优化。 ```sql CREATE INDEX idx_customer ON Orders(CustomerID); -- 非聚集索引1 CREATE INDEX idx_orderdate ON Orders(OrderDate); -- 非聚集索引2 ``` #### 2. **数据存储方式** [^1][^3] | **特性** | 聚集索引 | 非聚集索引 | |------------------|-----------------------------|-------------------------------| | **物理存储** | 数据行按索引顺序物理存储 | 数据行物理存储顺序不变 | | **叶节点内容** | 包含**完整数据行** | 包含**索引键值+行定位指针** | | **存储空间** | 不占用额外空间(即数据本身) | 需额外存储空间(独立结构)[^4] | > **示例说明**: > 当执行 `SELECT * FROM Orders WHERE OrderID=100` 时: > - 聚集索引:直接读取物理存储位置的数据行 > - 非聚集索引:先找到 `OrderID=100` 的指针,再通过指针定位数据行 #### 3. **查询性能** [^1][^4][^5] - **范围查询优势** 聚集索引在范围查询(如 `BETWEEN`、`>`)中效率更高: ```sql -- 聚集索引高效(数据物理连续) SELECT * FROM Orders WHERE OrderDate BETWEEN '2023-01-01' AND '2023-12-31'; ``` - **键查找开销** 非聚集索引需额外操作定位数据行(称为 **Key Lookup**): ```sql /* 非聚集索引执行过程: 1. 在索引树查找 CustomerID=5 的条目 2. 获取对应的行指针(RID或聚集键) 3. 通过指针回表获取完整数据 */ SELECT * FROM Orders WHERE CustomerID=5; ``` #### 4. **维护成本** [^1] | **操作** | 聚集索引影响 | 非聚集索引影响 | |----------------|-----------------------------|-----------------------------| | **INSERT** | 需重组数据保持物理顺序 | 仅更新索引结构 | | **UPDATE** | 可能引起数据位置移动 | 只更新索引条目 | | **DELETE** | 需整理数据碎片 | 删除索引条目 | > **典型场景**: > 频繁更新的列更适合非聚集索引,避免聚集索引的物理重组开销。 #### 5. **设计选择建议** - **优先聚集索引的列**: - 主键(默认创建聚集索引) - 范围查询频繁的列(如日期、数值序列) - 需要高并发顺序访问的列 - **优先非聚集索引的列**: - `WHERE` 子句中的过滤列 - `JOIN` 操作的关联列 - 需要覆盖索引的查询列 ```sql -- 覆盖索引优化(避免Key Lookup) CREATE INDEX idx_cover ON Orders(CustomerID) INCLUDE (OrderDate, Amount); ``` #### 6. **特殊注意事项** - **堆表(Heap)**:无聚集索引的表,数据无序存储,非聚集索引使用行指针(RID)定位 - **书签查找**:非聚集索引通过聚集键或RID定位数据的过程,可能成为性能瓶颈 - **包含列(INCLUDE)**:可扩展非聚集索引的覆盖范围,减少回表操作 > **性能对比公式**(简化模型)[^5]: > 聚集索引查询成本:$C_{clustered} = \log_B(N)$ > 非聚集索引查询成本:$C_{nonclustered} = \log_B(N) + \text{Lookup Cost}$ > (其中 $B$=树的分支因子,$N$=数据行数)
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值