postgresql主键自增推荐用identity(v10+,sql标准),次选serial(兼容旧版),底层均依赖sequence;手动管理sequence需注意权限、重置及冲突问题。

直接说结论:PostgreSQL 用 SEQUENCE,SQL Server / PostgreSQL 10+ / DB2 用 IDENTITY,但语义和行为差异很大,混用会出错。
PostgreSQL 中手动绑定 SEQUENCE 到主键
PostgreSQL 没有原生 IDENTITY(直到 v10 才引入,且默认仍推荐用 SEQUENCE),所以常见写法是显式创建并关联:
- 先建序列:
CREATE SEQUENCE users_id_seq START 1; - 建表时指定默认值:
id INTEGER PRIMARY KEY DEFAULT nextval('users_id_seq') - 插入时不传
id即可自动填充;若手动插入值,需确保不冲突,否则下次nextval()可能重复 - 如果后续想让序列“追上”当前最大
id,得手动重置:SELECT setval('users_id_seq', (SELECT MAX(id) FROM users));
SQL Server 的 IDENTITY 是列级属性,不能复用
SQL Server 的 IDENTITY(1,1) 是定义在列上的,不是独立对象:
- 建表即锁定:
id INT IDENTITY(1,1) PRIMARY KEY - 不能像 PostgreSQL 那样把同一个序列用于多个表;每个
IDENTITY列都独占一个内部计数器 - 插入时禁止显式指定该列值(除非先
SET IDENTITY_INSERT table ON),否则报错:Cannot insert explicit value for identity column - 重置计数器用:
DBCC CHECKIDENT ('table_name', RESEED, 100);—— 注意这不会检查已有数据是否冲突
PostgreSQL 10+ 的 GENERATED ALWAYS AS IDENTITY 更接近 SQL 标准
这是标准语法,但底层仍是基于 SEQUENCE,只是封装得更严:
- 建表:
id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY - 插入时若强行指定
id值,会报错:cannot insert into column "id"(除非加OVERRIDING SYSTEM VALUE) - 它自动创建并绑定一个序列,名字类似
table_name_col_name_seq,可通过\d table_name查看 - 和传统
SEQUENCE相比,它禁止意外覆盖、自动管理依赖关系,更适合新项目
跨数据库移植时最常踩的坑
你以为换方言只改关键字?实际行为差异藏在细节里:
-
SEQUENCE是独立对象,可被多个表/列共享;IDENTITY(SQL Server / Oracle)是列绑定的,不可共享 - PostgreSQL 的
nextval()是“预分配”,事务回滚后值不退还,会导致跳号;SQL Server 的IDENTITY在崩溃后也可能跳号(因缓存) - 迁移工具(如 Flyway/Liquibase)对
IDENTITY的识别不一致:有的把GENERATED ALWAYS AS IDENTITY当作普通默认值处理,漏掉序列依赖 - 备份还原时,PostgreSQL 的
SEQUENCE当前值不会随表数据自动同步,必须显式setval()或用pg_dump -s导出序列状态
真正麻烦的从来不是“怎么写出来”,而是“删掉旧数据再导入后,下一条插入会不会主键冲突”。这种问题往往在压测或上线后才暴露,而且只在特定数据库版本组合下发生。











