好的!以下是对 SQL 主键(Primary Key) 的详细讲解,涵盖其核心概念、作用、实现方式及实际应用。
一、主键的定义
主键(Primary Key) 是数据库表中用于唯一标识每一行数据的一个或一组字段(列)。它的核心目标是确保数据的唯一性 和完整性。
二、主键的特性
-
唯一性
- 主键的值必须在表中唯一,不能重复。
- 如果主键由多个列组成(复合主键),则这些列的组合值必须唯一。
-
非空性(NOT NULL)
- 主键字段的值不能为
NULL
,必须始终有值。
- 主键字段的值不能为
-
不可变性
- 主键的值一旦创建,应尽量避免修改,以维护数据关系的稳定性。
-
高效性
- 主键通常会被自动创建索引(如聚集索引),以提高查询速度。
三、主键的作用
-
唯一标识记录
确保表中每一行数据都有唯一的标识符,避免数据重复。
-
加速数据检索
主键自动创建索引,通过主键查询数据时速度更快。
-
维护数据完整性
作为外键(Foreign Key)的引用目标,确保表之间的关联关系正确。
-
优化数据存储
在部分数据库(如 MySQL InnoDB)中,主键决定了数据的物理存储顺序。
四、主键的实现方式
1. 单列主键
用一个单独的列作为主键,最常见的方式。
示例:
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100)
);
2. 复合主键(Composite Primary Key)
由多个列组合成主键,适用于单个列无法唯一标识数据的情况。
示例:
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
3. 自增主键(Auto Increment)
常用于生成唯一的主键值,适用于无业务含义的代理键(Surrogate Key)。
示例(MySQL):
CREATE TABLE employees (
emp_id INT AUTO_INCREMENT PRIMARY KEY,
emp_name VARCHAR(50)
);
示例(SQL Server):
CREATE TABLE employees (
emp_id INT IDENTITY(1,1) PRIMARY KEY,
emp_name VARCHAR(50)
);
4. 自定义主键
使用有业务意义的字段作为主键(自然键),如身份证号、订单号等。需确保值的唯一性和稳定性。
五、主键与索引的关系
- 主键自动创建唯一索引(Unique Index)。
- 在大多数数据库中,主键默认是聚集索引(Clustered Index),即数据按主键顺序物理存储(如 MySQL InnoDB)。
- 可以手动指定为非聚集索引(如 SQL Server)。
六、主键约束(Primary Key Constraint)
主键约束是数据库强制执行的规则,确保主键的唯一性 和非空性。如果插入重复值或空值,数据库会抛出错误。
七、主键的选择策略
-
代理键 vs 自然键
- 代理键 :无业务意义的自增ID(如
INT AUTO_INCREMENT
),推荐大多数场景使用。 - 自然键:有业务意义的字段(如身份证号),需确保长期唯一性。
- 代理键 :无业务意义的自增ID(如
-
数据类型选择
- 推荐使用整数类型(
INT
,BIGINT
)作为主键,因其查询和索引效率更高。 - 避免使用长字符串(如
VARCHAR(255)
)作为主键。
- 推荐使用整数类型(
-
复合主键的使用场景
- 当单个列无法唯一标识记录时使用(如订单项中的
order_id + product_id
)。 - 注意:复合主键可能导致外键设计更复杂。
- 当单个列无法唯一标识记录时使用(如订单项中的
八、主键设计的最佳实践
-
始终定义主键
即使没有明显的主键字段,也应添加代理键(如
id
列)。 -
避免频繁更新主键
修改主键会影响关联的外键和索引效率。
-
主键命名规范
推荐使用
pk_表名
的格式命名主键约束,提高可读性。
示例:
CREATE TABLE products (
product_id INT,
product_name VARCHAR(100),
CONSTRAINT pk_products PRIMARY KEY (product_id)
);
- 性能优化
- 自增主键的插入效率通常更高(顺序写入)。
- 复合主键的查询需注意最左前缀原则(Leftmost Prefix Principle)。
九、常见问题解答
Q1:主键可以为空吗?
不能! 主键字段必须定义为 NOT NULL
。
Q2:主键和唯一索引(UNIQUE)的区别?
- 主键不允许
NULL
,唯一索引允许一个NULL
(取决于数据库)。 - 一张表只能有一个主键,但可以有多个唯一索引。
Q3:如何删除主键?
ALTER TABLE table_name DROP PRIMARY KEY;
Q4:主键是否必须自增?
不是!自增只是生成主键的一种方式,也可手动指定值(需确保唯一)。
十、实际应用示例
场景:用户表设计
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY, -- 自增主键
username VARCHAR(50) NOT NULL UNIQUE, -- 唯一约束
email VARCHAR(100) NOT NULL
);
场景:订单与订单项关联
-- 订单表
CREATE TABLE orders (
order_id INT PRIMARY KEY,
order_date DATE
);
-- 订单项表(复合主键)
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id),
FOREIGN KEY (order_id) REFERENCES orders(order_id)
);