序列操作函数
序列是独立的取号对象,常用于主键默认值。它保证在适当配置下发号不重复,但不保证编号连续,也不能代表事务提交顺序。
取号与当前值
CREATE SEQUENCE invoice_number_seq START 100;
SELECT nextval('invoice_number_seq'); -- 首次为 100
SELECT currval('invoice_number_seq'); -- 本会话最近一次 nextval 得到的值
currval 要求本会话先对该序列调用 nextval,否则报错;其他连接的取号不会改变本会话的 currval。lastval() 取本会话最近一次调用 nextval 的序列值,在涉及多条序列时不如 currval('指定序列') 明确。
设置与表关联
SELECT setval('invoice_number_seq', 500, true);
-- 下一次 nextval 返回 501(默认步长 1)
SELECT setval('invoice_number_seq', 500, false);
-- 下一次 nextval 返回 500
pg_get_serial_sequence('public.orders', 'id') 可以查找与列关联的序列。新表主键优先考虑 GENERATED ... AS IDENTITY,而不是手写 nextval 默认值;插入后用 INSERT ... RETURNING id 获取本行生成的 ID,比事后查询全局状态可靠。
为什么出现空洞
nextval 的推进不会随事务回滚,失败插入、冲突处理、缓存以及会话终止都可能造成跳号。setval 的效果也不会按普通事务回滚,直接修改活跃序列可能与并发取号冲突。需要无空洞的业务编号时应另行设计串行化分配流程,接受相应吞吐量代价;不要用主键连续性推断丢失数据。示例 CREATE SEQUENCE 仅运行一次。