主键索引和唯一性索引的区别与联系
主键索引和唯一性索引的区别与联系
主键索引(Primary Key Index)和唯一性索(Unique Index)引都是索引,但它们在功能和特性上有明确的区别。
简单来说:主键索引是一种特殊的唯一性索引,它附带了更多的约束和语义。
核心总结
- 主键索引:是为主键约束自动创建的索引。它的核心是实现主键约束,即保证行的唯一标识符。一个表只能有一个。
- 唯一性索引:是为唯一性约束自动创建的索引,或者可以手动创建。它的核心是加速查询并保证数据唯一性。一个表可以有多个。
详细对比
下表详细对比了它们的区别:
特性 | 主键索引 | 唯一性索引 |
---|---|---|
创建方式 | 通过定义 主键约束 自动创建。 | 1. 通过定义 唯一性约束 自动创建。 2. 可以直接使用 CREATE UNIQUE INDEX 语句手动创建。 |
数量限制 | 一个表只能有一个主键索引。 | 一个表可以有多个唯一性索引。 |
是否允许NULL值 | 绝对不允许。主键列必须非空。 | 允许NULL值。具体规则与唯一性约束一致:大多数DBMS(如MySQL)允许多个NULL,因为NULL不相等;少数(如SQL Server)只允许一个NULL。 |
索引类型(默认) | 在多数数据库(如 SQL Server, MySQL的InnoDB)中,主键索引默认为 聚集索引。这意味着表数据本身会按照主键的顺序物理存储。 | 默认为非聚集索引。索引和数据是分开存储的,索引中只包含指向数据行的指针。 |
逻辑关联 | 与表的实体完整性紧密绑定,是逻辑设计的核心。通常作为外键引用的目标。 | 更多是性能优化和数据完整性的工具,体现业务规则。 |
是否可以被其他表引用为外键 | 是,这是主键的主要用途之一。 | 可以,但不太常见。虽然数据库技术上允许外键引用唯一性索引(而不仅仅是主键),但在逻辑设计中,这通常不是最佳实践。 |
关键点深入探讨:聚集索引
这是两者最核心的物理区别。
-
主键索引(通常为聚集索引):想象一本书的目录。在聚集索引中,数据页就是书的页码本身,内容严格按照页码(主键)顺序排列。当你通过主键查找时,数据库能直接定位到数据所在的数据页,效率极高。因为数据物理上只能有一种排序方式,所以一个表只能有一个聚集索引。
-
唯一性索引(通常为非聚集索引):想象一本书末尾的索引(比如,术语索引)。索引项(如“数据库”)后面跟的是它出现的页码列表,而不是内容本身。你需要先查这个“索引”,找到页码,再根据页码去对应的页查找具体内容。非聚集索引和数据的物理顺序无关,因此一个表可以创建很多个。
重要例外:在有些数据库如 Oracle 中,默认情况下,索引组织表(IOT)才将主键作为聚集索引,而普通表的存储是堆表,主键索引也是非聚集的。但 SQL Server 和 MySQL(InnoDB) 的默认行为是主键即聚集索引。
举例说明
还是以 用户表 (Users)
为例:
CREATE TABLE Users (user_id INT PRIMARY KEY AUTO_INCREMENT, -- 主键约束 -> 自动创建主键索引(聚集索引)username VARCHAR(50) UNIQUE, -- 唯一约束 -> 自动创建唯一性索引(非聚集索引)email VARCHAR(100),phone VARCHAR(20)
);-- 也可以手动为 email 创建一个唯一性索引,即使没有唯一约束
CREATE UNIQUE INDEX idx_unique_email ON Users(email);
在这个表中:
- 主键索引 (
PRIMARY
):建立在user_id
上。表的数据行在磁盘上大致是按照user_id
从小到大存储的。 - 唯一性索引 (
username
):自动为username
列创建。它是一个独立的结构,包含排序后的username
和对应的user_id
(主键值)。 - 唯一性索引 (
idx_unique_email
):我们手动为email
创建,功能上和自动创建的没有区别。
查询过程对比:
SELECT * FROM Users WHERE user_id = 5;
- 数据库使用聚集索引(主键索引),可以直接找到存储该行数据的磁盘位置,效率最高。
SELECT * FROM Users WHERE username = 'alice';
- 数据库先使用非聚集索引(username上的唯一索引) 找到
username
为 ‘alice’ 的条目,从中取出对应的user_id
(比如是 5)。 - 然后再用这个
user_id = 5
去聚集索引(主键索引) 中进行一次查找(这个过程称为 书签查找 或 回表),最终拿到所有数据。
- 数据库先使用非聚集索引(username上的唯一索引) 找到
总结与选择
场景 | 选择 |
---|---|
需要唯一标识每一行,并希望数据按此顺序物理存储以获得最佳主键查询性能。 | 使用主键约束(自动创建主键索引)。 |
需要确保某个业务字段(如邮箱、手机号)的唯一性,并加速按该字段的查询。 | 使用唯一性约束 或 手动创建唯一性索引。 |
表中已经有一个自然的主键(如user_id ),但还有另一组列需要唯一性(如项目ID 和成员ID 组合唯一)。 | 为这组列创建唯一性索引。 |
简单记住:主键索引是“唯一标识+数据物理顺序”,而唯一性索引是“保证唯一+加速查询”。