psql upsert导致非连续ID

时间:2018-08-01 10:59:25

标签: postgresql psql

我有一个带有primary_key id和唯一键col的postgresql(> 9.5)表。当我使用

INSERT INTO table_a (col) VLUES('xxx') ON CONFLICT(col) DO NOTHING;

要执行upsert,假设生成了一个ID为1的行。

如果我再次运行sql,什么也不会发生,但实际上ID 2会生成并被放弃。

然后,如果我插入新记录,例如

INSERT INTO table_a (col) VLUES('yyy') ON CONFLICT(col) DO NOTHING;

将生成另一个ID为3的行,并且浪费了ID 2

有没有避免这种浪费的东西?

1 个答案:

答案 0 :(得分:1)

大概idserial。在幕后,这会导致来自序列的nextval()调用。返回的数字nextval()将不再返回。并且nextval()的调用发生在检查可能的冲突之前。

来自"9.16. Sequence Manipulation Functions"

  

nextval

     

(...)

     

重要:为避免阻塞从同一序列中获取数字的并发事务,切勿回滚nextval操作;也就是说,一旦获取了值,就将其视为已使用且不会再次返回。即使周围的事务稍后中止,或者调用查询最终不使用该值也是如此。例如,带有INSERT子句的ON CONFLICT将计算要插入的元组,包括进行任何必需的nextval调用,然后再检测到可能导致其遵循{{ 1}}规则。这样的情况将在分配值的序列中留下未使用的“漏洞”。因此,PostgreSQL序列对象无法用于获取“无间隙”序列。

结论是,您的问题的答案是否定的,除非您以某种方式自行生成值,否则无法避免。