你有没有遇到过:删不掉重复数据,或者一加新记录就报“Duplicate entry”错误?
这十有八九,是主键(primary key)没设对。别慌——它真没听起来那么吓人。今天咱们就用大白话,把“primary key”从概念到例子,掰开揉碎讲清楚。
什么是 primary key?先说人话版定义
- *主键,就是一张表里唯一能“指名道姓”认出某一行的字段(或字段组合)**。
它像身份证号之于人:不能空、不能重复、全表唯一。
举个最直白的例子??
“`sql
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(50)
);
“`
这里 `id` 就是主键——以后每新增一条用户,系统会强制检查:这个 `id` 之前有没有用过?是不是 NULL?没通过?直接拦住,不让你插进去。
> ?? 我自己的体会:刚学时总以为“主键=自动编号”,其实不是。它可以是手机号(如果业务保证不重复)、订单号(如“ORD20240521001”),甚至邮箱——只要满足“非空+唯一”就行。
# 主键的三个铁律,记牢就少踩80%的坑
- 非空性:主键字段值绝不允许是 NULL(数据库直接拒绝插入)
- 唯一性:整张表里,这个值只能出现一次,多一次都不行
- 不可更改性(建议):虽然技术上可以 UPDATE 主键,但极不推荐——外键关联、日志追踪、缓存逻辑全会乱套
? 正确做法:用自增 ID 或 UUID 做主键,安心省心。
? 反面案例:用“姓名”当主键?重名怎么办?用“城市名”?全国几十个北京镇……立马崩。
复合主键:两个字段一起当“身份证”,什么场景非用不可?
有时候,单个字段压根没法唯一标识一行。比如这张订单明细表:
|
order_id | product_id | quantity |
|———-|————|———-|
| 1001 | P005 | 2 |
| 1001 | P007 | 1 |
| 1002 | P005 | 3 |
你看:`order_id` 单独不唯一(一个订单买多个商品),`product_id` 单独也不唯一(同一商品被不同订单买)。但 `order_id + product_id` 组合起来,就天然唯一了——同一个订单里,不可能重复添加同一款商品两次。
所以建表时这样写:
“`sql
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
“`
> ?? 我的看法:复合主键不是炫技,而是对业务逻辑的诚实表达。强行塞个无意义自增ID,反而让表结构“失真”。但前提是:这两个字段真的稳定、可预测、不常变。
初学者最容易卡壳的3个问题(自问自答)
- *Q:主键和索引是什么关系?**
A:主键自动创建唯一索引,所以查询快——但这不是它的主要目的。它的核心使命是保证数据完整性,索引只是顺带福利。
- *Q:一张表能有几个主键?**
A:只能有一个。但这个主键可以由1个字段构成(单列主键),也可以由2个及以上字段构成(复合主键)。
- *Q:主键一定要自增吗?**
A:完全不用。MySQL 默认支持自增,但 PostgreSQL 常用 UUID,MongoDB 根本没有传统主键概念……关键是看你的业务要不要分布式、要不要隐藏增长规律。
最后聊句实在的:学主键,别死背定义。打开你的数据库工具,建两张表——一张用 `id INT PRIMARY KEY AUTO_INCREMENT`,另一张用 `(user_id, created_at)` 当复合主键,手动 INSERT 几条试试。报错几次,比看十篇教程都管用。
真实世界里,好设计往往藏在“不让错发生”的细节里。主键,就是第一道门禁。
© 版权声明
文章版权归作者所有,未经允许请勿转载。





