我有一个带有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
!
有没有避免这种浪费的东西?
答案 0 :(得分:1)
大概id
是serial
。在幕后,这会导致来自序列的nextval()
调用。返回的数字nextval()
将不再返回。并且nextval()
的调用发生在检查可能的冲突之前。
来自"9.16. Sequence Manipulation Functions":
nextval
(...)
重要:为避免阻塞从同一序列中获取数字的并发事务,切勿回滚
nextval
操作;也就是说,一旦获取了值,就将其视为已使用且不会再次返回。即使周围的事务稍后中止,或者调用查询最终不使用该值也是如此。例如,带有INSERT
子句的ON CONFLICT
将计算要插入的元组,包括进行任何必需的nextval
调用,然后再检测到可能导致其遵循{{ 1}}规则。这样的情况将在分配值的序列中留下未使用的“漏洞”。因此,PostgreSQL序列对象无法用于获取“无间隙”序列。
结论是,您的问题的答案是否定的,除非您以某种方式自行生成值,否则无法避免。