psql upsert 导致不连续的 id
psql upsert results in noncontinuous id
我有一个带有 primary_key id
和唯一键 col
的 postgresql (>9.5) table。当我使用
INSERT INTO table_a (col) VLUES('xxx') ON CONFLICT(col) DO NOTHING;
要执行更新插入,假设生成了一个 ID 为 1
的行。
如果我再次运行 sql,什么都不会发生,但实际上id 2
将被生成并被放弃。
然后如果我插入一条新记录,例如
INSERT INTO table_a (col) VLUES('yyy') ON CONFLICT(col) DO NOTHING;
将生成另一行id为3
的行,id为2
的行被浪费了!
有没有办法避免这种浪费?
推测id
是一个serial
。在幕后,这会导致来自序列的 nextval()
调用。一个数字 nextval()
一旦返回就不会再返回。 nextval()
的调用发生在检查可能的冲突之前。
来自 "9.16. Sequence Manipulation Functions":
nextval
(...)
Important: To avoid blocking concurrent transactions that obtain numbers from the same sequence, a nextval
operation is never rolled back; that is, once a value has been fetched it is considered used and will not be returned again. This is true even if the surrounding transaction later aborts, or if the calling query ends up not using the value. For example an INSERT
with an ON CONFLICT
clause will compute the to-be-inserted tuple, including doing any required nextval
calls, before detecting any conflict that would cause it to follow the ON CONFLICT
rule instead. Such cases will leave unused "holes" in the sequence of assigned values. Thus, PostgreSQL sequence objects cannot be used to obtain "gapless" sequences.
得出的结论是,您的问题的答案是否定的,除非您自己以某种方式生成值,否则无法避免这种情况。
我有一个带有 primary_key id
和唯一键 col
的 postgresql (>9.5) table。当我使用
INSERT INTO table_a (col) VLUES('xxx') ON CONFLICT(col) DO NOTHING;
要执行更新插入,假设生成了一个 ID 为 1
的行。
如果我再次运行 sql,什么都不会发生,但实际上id 2
将被生成并被放弃。
然后如果我插入一条新记录,例如
INSERT INTO table_a (col) VLUES('yyy') ON CONFLICT(col) DO NOTHING;
将生成另一行id为3
的行,id为2
的行被浪费了!
有没有办法避免这种浪费?
推测id
是一个serial
。在幕后,这会导致来自序列的 nextval()
调用。一个数字 nextval()
一旦返回就不会再返回。 nextval()
的调用发生在检查可能的冲突之前。
来自 "9.16. Sequence Manipulation Functions":
nextval
(...)
Important: To avoid blocking concurrent transactions that obtain numbers from the same sequence, a
nextval
operation is never rolled back; that is, once a value has been fetched it is considered used and will not be returned again. This is true even if the surrounding transaction later aborts, or if the calling query ends up not using the value. For example anINSERT
with anON CONFLICT
clause will compute the to-be-inserted tuple, including doing any requirednextval
calls, before detecting any conflict that would cause it to follow theON CONFLICT
rule instead. Such cases will leave unused "holes" in the sequence of assigned values. Thus, PostgreSQL sequence objects cannot be used to obtain "gapless" sequences.
得出的结论是,您的问题的答案是否定的,除非您自己以某种方式生成值,否则无法避免这种情况。