以下复合查询是否保证是原子的?

时间:2017-05-31 18:50:24

标签: multithreading postgresql

我想在复杂的COPY操作之前保留大量的对象ID。我知道setvalnextval有原子保证,但是如果我在复合语句中使用它们,如果在以下情况下使用它们,那么这些保证是否保留在多线程环境中?我正在使用postgresql 9.6。

SELECT setval('objects_id_seq', nextval('objects_id_seq') + 9999); -- returns the last reserved id

1 个答案:

答案 0 :(得分:0)

  

我知道setvalnextval有原子保证

是的,但保证可能不是您认为的那样。请记住,序列不受正常事务边界的限制。您的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行的跳转。你可能不在乎,但值得了解。我不建议你依赖这种行为。