如何在Postgres中将序列递增超过1?

3

如何在Postgres中原子地更新序列?

背景:我正在使用SQLAlchemy批量插入对象,但exectutemany无法返回默认值,因此我想将主键序列逐个增加我需要插入的对象数量。

我知道可以这样做:

ALTER SEQUENCE seq INCREMENT BY 1000;

但我不确定在并发环境下这样做是否安全。


ALTER SEQUENCE 不会立即影响除当前后端之外的其他后端的 nextval 结果,这些后端已经预分配(缓存)了序列值。它们将在注意到更改的序列生成参数之前使用完所有缓存的值。当前后端将立即受到影响。ALTER SEQUENCE 不会影响序列的 currval 状态。(在 PostgreSQL 8.3 之前,有时会影响。)ALTER SEQUENCE 阻塞并发的 nextval、currval、lastval 和 setval 调用。https://www.postgresql.org/docs/12/sql-altersequence.html它会阻塞其他操作,但是是安全的。 - Slava Lenskyy
3个回答

3
您可以使用 setval() 结合 nextval()
select setval('my_sequence', nextval('my_sequence') + 999);

这个操作会将当前值增加1000,而不是将其设置为固定值。


2
如Laurenz Albe所建议的:我调用了nextval 1000次。
SELECT nextval('common_id_seq') FROM generate_series(1, 1000);

与a_horse_with_no_name的建议相比,这种方法的优点是我不需要向用户授予setval权限。

1
这也会返回序列中的1000个值。如果您有一个高度并发的系统,是否可能在generate_series执行期间调用另一个nextval(),导致值不完全按顺序?(我猜这是可能的,所以如果您想为1000个项目分配ID,这是最安全的方法) - Kip
这实际上是一个非常好的观点。这可能意味着common_id可能与创建顺序不匹配,这对于依赖此项的容错系统可能会造成问题。把它放在某种锁后面可能是有意义的。 - Rol

1

这样做是安全的,因为ALTER SEQUENCE会在序列上获取一个ACCESS EXCLUSIVE锁。

但是存在两个问题:

  • 这将阻塞所有并发使用序列直到您的事务完成

  • 您不知道起始值

您可以通过以下方式解决第二个问题:

BEGIN;
ALTER SEQUENCE seq INCREMENT BY 1000;
SELECT nextval('seq');
COMMIT;

那么你知道这个值和前面的999个值都是属于你的。

但我认为最好的方法是调用nextval 1000次。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接