PostgreSQL约束导致INSERT失败但主键序列仍自增是否为预期行为?
问题结论
这是PostgreSQL的预期行为,不属于异常或Bug。
核心原因
序列的设计核心目标是保障高并发场景下高性能、无阻塞的唯一值生成,其最关键的特性就是值一旦被获取就不会回滚:
- 只要INSERT操作过程中调用了序列的
nextval()函数(无论是serial类型、IDENTITY自增列还是显式调用),对应的序列值就会被立刻标记为已使用。 - 后续不管INSERT因为唯一约束报错、其他约束校验失败、事务回滚等任何原因执行失败,已经消耗的序列值都不会被回收重分配。
设计逻辑
如果要实现序列值不被浪费,需要对序列加全局事务级锁,等待整个事务提交后再确认值的使用,这会导致高并发写入场景下出现严重的性能瓶颈,所有写入事务都会卡在序列值获取的步骤,完全违背了序列的设计初衷。
其他会触发序列跳号的常见场景
- 事务显式执行
ROLLBACK回滚 - 并发写入场景下,多个事务同时获取序列值后部分事务回滚
- 批量插入语句执行中途失败,已经获取的序列值不会被回收
补充说明
绝大多数业务场景下,自增主键只需要保证唯一性即可,跳号完全不影响正常使用,不需要做额外处理。如果你的业务确实要求主键完全连续无缺口,需要自行实现基于计数器表加行锁的自增逻辑,但该方案并发性能极低,仅适合写入量极小的场景。
内容的提问来源于stack exchange,提问作者Gregor Brandt
相关产品推荐
相关产品推荐

