MySQL需先确保列存在且非空,再用一条语句同时设NOT NULL、主键和AUTO_INCREMENT;PostgreSQL需建序列、绑定默认值、设主键并关联OWNED BY。
MySQL 里怎么给已有表批量加主键和自增列
直接加不行,alter table 一次只能改一个列的属性,而且主键必须非空、唯一、索引化,自增还要求是整型+主键(或主键的一部分)。常见错误是执行 alter table t1 modify id int auto_increment; 却报错 error 1075: incorrect table definition——因为没同时设主键。
实操建议:
- 先确保目标列存在且类型合适(如
INT或BIGINT),值全为NULL或可安全清空 - 用一条语句同时完成:设列为
NOT NULL+ 设为主键 + 开启AUTO_INCREMENT - 如果原表已有数据,得先补全该列值(比如用
UPDATE t1 SET id = (@i := @i + 1) ORDER BY some_col;初始化) - 注意:加
AUTO_INCREMENT后,SHOW CREATE TABLE显示的起始值默认是当前最大值 + 1;若想指定,得加AUTO_INCREMENT = N
示例:
ALTER TABLE users MODIFY id BIGINT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (id);
PostgreSQL 批量处理主键与序列(不是 AUTO_INCREMENT)
PostgreSQL 没有 AUTO_INCREMENT,靠 SERIAL 或显式序列实现。给已有表加“自增主键”,本质是三步:建序列 → 绑定到列 → 设默认值 → 设主键。容易踩的坑是漏掉 OWNED BY,导致后续 DROP TABLE 不自动删序列,或者默认值写成 nextval('seq') 却忘了设 NOT NULL。
实操建议:
- 用
CREATE SEQUENCE创建新序列,命名建议带表名前缀(如users_id_seq) - 用
ALTER TABLE ... ALTER COLUMN ... SET DEFAULT绑定默认值,必须写完整函数调用nextval('users_id_seq'::regclass) - 用
ALTER TABLE ... ADD PRIMARY KEY加主键;若列原为NULL,得先ALTER COLUMN ... SET NOT NULL - 最后用
ALTER SEQUENCE ... OWNED BY关联,否则 pg_dump 不会导出依赖关系
示例:
CREATE SEQUENCE users_id_seq; ALTER TABLE users ALTER COLUMN id TYPE BIGINT, ALTER COLUMN id SET DEFAULT nextval('users_id_seq'), ALTER COLUMN id SET NOT NULL; ALTER TABLE users ADD PRIMARY KEY (id); ALTER SEQUENCE users_id_seq OWNED BY users.id;
批量脚本里怎么安全跳过已设主键的表
写 shell 或 Python 脚本批量处理几十张表时,最怕重复执行导致报错中断。MySQL 中查是否已有主键,看 INFORMATION_SCHEMA.KEY_COLUMN_USAGE;PostgreSQL 看 pg_constraint。但别只查“有没有主键”,还得确认是不是你打算用的那列——比如表已有 uuid 主键,你还硬要加 id 自增,就冲突了。
实操建议:
- MySQL 判断:查
SELECT COUNT(*) FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_SCHEMA = 'db' AND TABLE_NAME = 't' AND CONSTRAINT_NAME = 'PRIMARY' AND COLUMN_NAME = 'id'; - PostgreSQL 判断:查
SELECT 1 FROM pg_constraint c JOIN pg_attribute a ON a.attnum = ANY(c.conkey) AND a.attrelid = c.conrelid WHERE c.conrelid = 't'::regclass AND c.contype = 'p' AND a.attname = 'id'; - 脚本中把判断逻辑封装成函数,返回 0 表示“可操作”,非 0 表示“跳过”
- 所有
ALTER操作加IF NOT EXISTS(MySQL 8.0.19+ / PG 12+ 支持)仍不够,因为主键本身不支持这个语法,得靠前置判断
为什么不能直接在从库上执行这类 DDL
主从延迟下加主键可能卡住复制线程,尤其大表 ALTER TABLE 会锁表(MySQL 5.6+ 的 ALGORITHM=INPLACE 也并非完全无锁)。更隐蔽的问题是:某些 ORM 或中间件(如 ShardingSphere)依赖主键做路由或分页,一旦从库结构不一致,查询结果就错位。
实操建议:
- 所有 DDL 必须在主库执行,且避开业务高峰;提前用
pt-online-schema-change(MySQL)或pg_repack(PG)评估影响 - 确认从库 SQL 线程状态为
Slave_SQL_Running: Yes,且Seconds_Behind_Master接近 0 再开始 - 如果表上有外键,MySQL 会拒绝加主键直到先删外键;PostgreSQL 则允许,但后续插入可能因外键引用失败
- 加完立刻验证:查
SELECT COUNT(*) FROM t WHERE id IS NULL,结果必须为 0;再查INSERT是否真生成新值
物理设计效率提升的关键,从来不在“批处理”的动作有多快,而在于每一步是否能预判约束条件、规避隐式依赖、留好回滚路径。尤其是跨环境同步或 ORM 自动生成 schema 的场景,列定义和约束的微小偏差,后期排查成本远高于初期多花两分钟验证。










