必须先查并修复重复值和null值,再显式声明所有参与列not null,最后添加联合主键;mysql校验严格,只认列定义是否not null,不看当前数据是否为空。

查重复和 NULL 值是第一步,跳过就必然失败
直接 ALTER TABLE table_name ADD PRIMARY KEY (a, b) 几乎肯定报错,错误通常是 Duplicate entry 'X,Y' for key 'PRIMARY' 或 Column 'a' cannot be null。MySQL 在加主键前会全表扫描校验,只要有一行不满足「所有参与列非空 + 组合值唯一」,就中止并报错。
必须先查:
- 查组合重复:
SELECT a, b, COUNT(*) FROM table_name GROUP BY a, b HAVING COUNT(*) > 1 - 查任一列为 NULL:
SELECT * FROM table_name WHERE a IS NULL OR b IS NULL
修复方式按业务定:删冗余行、用 UPDATE SET a = ... , b = ... 补值(注意类型兼容),或用 UUID_SHORT() 生成新组合(仅限整数列)。
所有参与列必须显式声明 NOT NULL
即使当前数据里 a 和 b 都没有 NULL 值,只要建表时没定义 NOT NULL,ADD PRIMARY KEY 仍会失败。MySQL 只看列定义,不看数据快照。
执行顺序不能错:
- 先改列定义:
ALTER TABLE table_name MODIFY COLUMN a INT NOT NULL - 再改另一列:
ALTER TABLE table_name MODIFY COLUMN b VARCHAR(32) NOT NULL - 最后加主键:
ALTER TABLE table_name ADD PRIMARY KEY (a, b)
如果列类型是 VARCHAR、TEXT 等,注意长度限制和字符集;MODIFY 会重建列,大表慎用。
联合主键的字段顺序直接影响查询可用性
联合主键 (order_id, product_id) 和 (product_id, order_id) 是两个完全不同的索引结构。
WHERE 条件能否走索引,取决于最左前缀原则:
-
WHERE order_id = 123✅ 能用上 -
WHERE order_id = 123 AND product_id = 456✅ 能用上 -
WHERE product_id = 456❌ 无法使用该联合主键索引
顺序要按高频查询条件排列,而不是按“业务逻辑谁更重要”。如果常单独查 product_id,它就不该放在第二位——考虑是否真需要联合主键,或补一个单列索引。
已有主键时不能 ADD,只能 DROP 再 ADD
MySQL 不支持修改主键,也不允许一个表存在多个主键。如果表已有主键(比如单列 id),直接 ADD PRIMARY KEY (a, b) 会报错 Multiple primary key defined。
必须分两步:
- 先删旧主键:
ALTER TABLE table_name DROP PRIMARY KEY - 再加新联合主键:
ALTER TABLE table_name ADD PRIMARY KEY (a, b)
注意:DROP PRIMARY KEY 不需要指定名称,MySQL 自动识别唯一主键约束;但删完后原主键列的 NOT NULL 和 AUTO_INCREMENT 属性不会自动保留,如有依赖需手动补回。
最容易被忽略的是:列定义里的 NOT NULL 和数据实际无 NULL 是两回事,而 MySQL 只认前者。哪怕你刚用 UPDATE 把所有 NULL 补完了,不改列定义,加主键照样失败。











