我想在复杂的COPY操作之前保留大量的对象ID。我知道setval
和nextval
有原子保证,但是如果我在复合语句中使用它们,如果在以下情况下使用它们,那么这些保证是否保留在多线程环境中?我正在使用postgresql 9.6。
SELECT setval('objects_id_seq', nextval('objects_id_seq') + 9999); -- returns the last reserved id
答案 0 :(得分:0)
我知道
setval
和nextval
有原子保证
是的,但保证可能不是您认为的那样。请记住,序列不受正常事务边界的限制。您的setval
将立即对其他并发事务生效。它是原子的 - 它要么全部发生,要么根本不发生 - 但这并不意味着它服从所有的ACID属性。
您的查询肯定会影响并发查询。具体而言,如果来自其他查询的并发nextval
调用,则序列的值将在setval
与后续nextval
之间继续增加。因此,如果您的意图是"保留9999个ID"它不会起作用,如果10个其他会话称为“nextval'在你的nextval和setval之间的小窗口中。
您也不能LOCK
来自SQL的序列,因此您无法对其进行EXCLUSIVE
锁定。
你可以:
EXCLUSIVE
模式下使用序列的表格,并希望没有人直接在序列上同时调用nextval(...)
; COPY
像往常一样从DEFAULT nextval(....)
分配生成的密钥; 在这种情况下,我认为您真正想要的是nextval
变体,它会按您提供的值递增,例如9999,而不是1. PostgresSQL还没有这样的功能,但拥有一个功能真的很方便。欢迎补丁!
您可能在考虑"如果我ALTER SEQUENCE ... INCREMENT 9999
然后调用nextval
然后调用ALTER SEQUENCE ... INCREMENT 1
该怎么办?是的,不要那样做。遗憾的是,ALTER SEQUENCE
的效果 也会在事务边界外变得可见,因为nextval
工作的属性相同。因此,调用nextval
的并发查询也可能会获得9999行的跳转。你可能不在乎,但值得了解。我不建议你依赖这种行为。