唯一索引,主键索引,聚集索引

本文深入探讨了 SQL Server 中的主键、唯一索引和聚集索引的概念、作用及区别,解释了它们如何影响数据库性能与数据一致性。
表通常具有包含唯一标识表中每一行的值的一列或一组列。这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性。在创建或修改表时,您可以通过定义 PRIMARY KEY 约束来创建主键。
-
主键(PRIMARY KEY )
来自MSDN的描述:
表通常具有包含唯一标识表中每一行的值的一列或一组列。这样的一列或多列称为表的主键 (PK),用于强制表的实体完整性。在创建或修改表时,您可以通过定义 PRIMARY KEY 约束来创建主键。
一个表只能有一个 PRIMARY KEY 约束,并且 PRIMARY KEY 约束中的列不能接受空值。由于 PRIMARY KEY 约束可保证数据的唯一性,因此经常对标识列定义这种约束。
如果为表指定了 PRIMARY KEY 约束,则 SQL Server 2005 数据库引擎 将通过为主键列创建唯一索引来强制数据的唯一性。当在查询中使用主键时,此索引还可用来对数据进行快速访问。因此,所选的主键必须遵守创建唯一索引的规则。
创建主键时,数据库引擎 会自动创建唯一的索引来强制实施 PRIMARY KEY 约束的唯一性要求。如果表中不存在聚集索引或未显式指定非聚集索引,则将创建唯一的聚集索引以强制实施 PRIMARY KEY 约束。

聚集索引
聚集索引基于数据行的键值在表内排序和存储这些数据行。每个表只能有一个聚集索引,因为数据行本身只能按一个顺序存储。
每个表几乎都对列定义聚集索引来实现下列功能:
-可用于经常使用的查询。
-提供高度唯一性。

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~``

主键是唯一的,所以创建了一个主键的同时,也就这个字段创建了一个唯一的索引,

    唯一索引实际上就是要求指定的列中所有的数据必须不同。

    主键一唯一索引的区别:

         1 一个表的主键只能有一个,而唯一索引可以建多个
         2 主键可以作为其它表的外键。
         3 主键不可为null,唯一索引可以为null

聚集索引:将表内的数据按照一定的规则进行排列的目录。正因为如此,一个表中的聚焦索引只有一个。对此我们要注意“主键就是聚焦索引”这是极端错 误的,是对聚焦索引的一种浪费。(虽然SQLServer默认主键就是聚焦索引)使用聚焦索引的最大好处就是按照查询要求,迅速缩小查询范围,避免进行全 表扫描。其次让每个数目都不相同的字段作为聚焦索引也不符合“大数目不同情况下不应建立聚集索引的原则”。

一、索引的作用

1、帮助检索数据;

2、提高联接效率;

3、节省ORDER BY、GROUP BY的时间;

4、保证数据唯一性(仅限于唯一索引)。




二、索引的设计

在确定要建立一个索引时,首先我们要确定它是聚集还是非聚集、单列还是多列、唯一还是非唯一、列是升序还是降序、它的存储是如何的,比如:分区、填充因子等。下面逐条来看:

1、聚集索引

(1)首先指出一个误区,主键并不一定是聚集索引,只是在SQL SERVER中,未明确指出的情况下,默认将主键定义为聚集,而ORACLE中则默认是非聚集,因为SQL SERVER中的ROWID未开放使用。

(2)聚集索引适合用于需要进行范围查找的列,因为聚集索引的叶子节点存放的是有序的数据行,查询引擎可根据WHERE中给出的范围,直接定位到两端的叶子节点,将这部分节点页的数据根据链表顺序取出即可;

(3)聚集索引尽量建立在值不会发生变更的列上,否则会带来非聚集索引的维护;

(4)尽量在建立非聚集索引之建立聚集索引,否则会导致表上所有非聚集索引的重建;

(5)聚集索引应该避免建立在数值单调的列上,否则可能会造成IO的竞争,以及B树的不平衡,从而导致数据库系统频繁的维护B树的平衡性。聚集索引的列值最好能够在表中均匀分布。

3、唯一索引

(1)再指出一个误区,聚集索引并不一定是唯一索引,由于SQL SERVER将主键默认定义为聚集索引,事实上,索引是否唯一与是否聚集是不相关的,聚集索引可以是唯一索引,也可以是非唯一索引;

(2)将索引设置为唯一,对于等值查找是很有利的,当查到第一条符合条件的纪录时即可停止查找,返回数据,而非唯一索引则要继续查找,同样,由于需要保证唯一性,每一行数据的插入都会去检查重复性; 
<think>我们正在讨论唯一索引主键的关系。根据引用内容,我们可以总结以下几点: 1. **主键是一种约束,唯一索引是一种索引**(引用[1])。 2. **主键不能为NULL,唯一索引可以为NULL**(引用[1])。 3. **一张表只能有一个主键,但可以有多个唯一索引**(引用[1])。 4. **主键创建后一定包含一个唯一索引,但唯一索引不一定是主键**(引用[1])。 5. **主键可以做为外键,唯一索引不行**(引用[1])。 6. **主键索引唯一索引的特殊类型**(引用[2])。 7. **主键相当于逻辑键,索引相当于物理键**(引用[3])。 8. **如果设置了主键,那么主键就是聚簇索引**(引用[4])。 因此,唯一索引并不等同于主键,它们有相似之处(都要求值唯一),但也有重要区别。 ### 核心区别总结 | **特性** | **主键** | **唯一索引** | |------------------|------------------------------|---------------------------| | **本质** | 约束(自动创建唯一索引) | 索引类型 | | **数量限制** | 每表仅一个 | 每表可多个 | | **NULL值** | 不允许NULL | 允许NULL(除非指定NOT NULL)| | **外键关联** | 可作为外键引用 | 不可作为外键引用 | | **聚簇索引** | 通常是聚簇索引(InnoDB) | 通常是非聚簇索引 | | **逻辑/物理** | 逻辑标识(页码)[^3] | 物理结构(目录)[^3] | ### 详细说明 1. **主键的特殊性** - 主键不仅是唯一索引,还附加了**非空约束**(`NOT NULL`)和**实体完整性约束**(确保每行可唯一标识)[^1][^2]。 - 在InnoDB引擎中,主键默认作为**聚簇索引**(数据按主键顺序物理存储)[^4],而唯一索引是非聚簇索引(独立于数据存储)。 2. **唯一索引的灵活性** - 唯一索引允许`NULL`值(除非列定义为`NOT NULL`),且可存在多个`NULL`值(因为`NULL`不等于任何值,包括自身)[^1]。 - 唯一索引可作用在非主键列上,例如用户表中的邮箱、身份证号等需要唯一但非主键的字段[^5]。 3. **使用场景差异** - **主键**:用于唯一标识行,是表的核心逻辑标识(如用户ID、订单ID)[^3]。 - **唯一索引**:用于避免重复值,但不作为核心标识(如避免重复邮箱、手机号)[^5]。 ### 示例说明 #### 创建主键(自动生成唯一索引) ```sql CREATE TABLE Users ( id INT PRIMARY KEY, -- 主键(自动创建唯一索引) email VARCHAR(100) UNIQUE -- 唯一索引(非主键) ); ``` - `id` 是主键:不允许`NULL`,且自动成为聚簇索引(InnoDB)[^4][^5]。 - `email` 是唯一索引:允许`NULL`(除非显式指定`NOT NULL`),且可重复插入多个`NULL`值[^1]。 #### 查询验证 ```sql INSERT INTO Users (id, email) VALUES (1, 'a@test.com'); -- 成功 INSERT INTO Users (id, email) VALUES (2, NULL); -- 成功(唯一索引允许NULL) INSERT INTO Users (id, email) VALUES (3, NULL); -- 成功(NULL不视为重复) INSERT INTO Users (id, email) VALUES (4, 'a@test.com'); -- 失败(违反唯一索引) ``` ### 结论 > **唯一索引主键** > - 主键是特殊的唯一索引(附加非空约束和实体完整性),但唯一索引不一定是主键。 > - 主键在功能上更严格(不可为`NULL`、仅能有一个),而唯一索引更灵活(允许多个、可包含`NULL`)[^1][^2][^4]。 --- §§ 相关问题 §§ 1. 主键唯一索引在查询性能上有差异吗? 2. 聚簇索引和非聚簇索引如何影响数据存储? 3. 如何选择主键唯一索引的使用场景? 4. 唯一索引允许NULL值会带来什么潜在问题? 5. 在哪些情况下应该使用联合主键?</think>### 唯一索引主键的关系解析 **核心结论:唯一索引不等同于主键**,它们是两个有交集但本质不同的概念。以下是关键区别: | **特性** | **主键** | **唯一索引** | |------------------|------------------------------|---------------------------| | **本质** | 约束(自动创建唯一索引) | 索引类型 | | **数量限制** | 每表仅一个 | 每表可多个 | | **NULL值** | 绝对禁止NULL | 允许NULL(除非指定NOT NULL)| | **外键关联** | 可作为外键引用 | 不可作为外键引用 | | **聚簇索引** | 默认成为聚簇索引(InnoDB) | 通常是非聚簇索引 | | **逻辑意义** | 实体唯一标识(如身份证号) | 数据唯一性保证 | --- ### 🔍 深度解析 #### 1. **主键包含唯一索引,但反之不成立** - 创建主键时会**自动生成唯一索引**(物理实现)[^5],但唯一索引本身只是索引结构,不包含主键的约束特性[^1][^2]。 - **示例**: ```sql ALTER TABLE users ADD PRIMARY KEY (id); -- 自动创建唯一索引 ALTER TABLE users ADD UNIQUE (email); -- 仅创建唯一索引 ``` #### 2. **NULL值的根本差异** - 主键列**绝对不允许NULL**(违反实体完整性)[^1][^4] - 唯一索引列**允许NULL值**(除非显式指定`NOT NULL`) ```sql INSERT INTO users (email) VALUES (NULL); -- 允许(唯一索引) INSERT INTO users (id) VALUES (NULL); -- 报错(主键禁止NULL) ``` #### 3. **聚簇索引的绑定关系** - 在InnoDB引擎中,主键默认成为**聚簇索引**(数据按主键顺序物理存储)[^4] - 唯一索引通常是**二级索引**(叶子节点存储主键值,需回表查询)[^4] #### 4. **功能扩展性对比** | **能力** | 主键 | 唯一索引 | |------------------|------|----------| | 保证行唯一性 | ✅ | ✅ | | 作为外键引用目标 | ✅ | ❌ | | 允许部分字段为NULL | ❌ | ✅ | | 支持多列组合 | ✅ | ✅ | --- ### 💡 使用场景建议 1. **用主键当** - 核心业务标识(用户ID、订单号) - 需要作为外键引用的字段 - 需要利用聚簇索引加速范围查询的场景 2. **用唯一索引当** - 辅助唯一字段(邮箱、手机号) - 允许空值的唯一约束字段 - 已存在主键时的附加唯一性保障 --- ### ⚠️ 经典误区 **错误认知**: > “主键唯一索引都能保证唯一性,所以可以互换使用” **正解**: - 主键是**实体完整性的核心实现**(如InnoDB的聚簇索引依赖主键)[^4] - 唯一索引是**数据完整性的辅助工具**(可存在多个,不承担核心标识作用)[^3] --- ### 🌰 实例验证 ```sql CREATE TABLE employees ( emp_id INT PRIMARY KEY, -- 主键(非空+唯一索引) ssn CHAR(11) UNIQUE NOT NULL, -- 唯一索引(显式非空) email VARCHAR(100) UNIQUE -- 唯一索引(允许NULL) ); -- 有效插入 INSERT INTO employees VALUES (1, '123-45-6789', 'a@test.com'); INSERT INTO employees VALUES (2, '987-65-4321', NULL); -- 无效操作 INSERT INTO employees VALUES (NULL, '111-22-3333', 'b@test.com'); -- 主键不能NULL INSERT INTO employees VALUES (3, '123-45-6789', 'c@test.com'); -- 违反唯一索引 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值