Re: Concurrent INSERT statements with RETURNING clause resetting SERIAL sequence - Mailing list pgsql-general

From Francisco Olarte
Subject Re: Concurrent INSERT statements with RETURNING clause resetting SERIAL sequence
Date
Msg-id CA+bJJbwztA5p8zpyAu2O2ny8Sc2dwOp=j3Y-jfWvgErcTGQ_PQ@mail.gmail.com
Whole thread Raw
In response to Re: Concurrent INSERT statements with RETURNING clause resetting SERIAL sequence  (Sebastien Flaesch <sebastien.flaesch@4js.com>)
Responses Re: Concurrent INSERT statements with RETURNING clause resetting SERIAL sequence  (Gavan Schneider <list.pg.gavan@pendari.org>)
List pgsql-general
On Tue, 19 Jul 2022 at 18:50, Sebastien Flaesch
<sebastien.flaesch@4js.com> wrote:
>> If that's the behavior you want, you can build it out of standard SQL facilities (e.g. update a one-row table).
> Can you elaborate please?
> Do you mean the code should use an UPDATE on a one-row table to acquire a lock?

That's the usual SQL way. You can, using the appropiate isolation
level, select the max() from the table using the IDs  ( but this will
probably lock it whole ), you can use a one-row table with a current
int column as a sequence, and set current=current+1, but this will
lock everyone inserting ( and need an extra table ). You can use a
name-current unique sequences table and update that ( it saves tables
but it can worsen locking, as many engines locks whole pages ). The
consecutive gapless sequence problem surfaces a lot, but there is no
good way to solve it without locking, as once you get the value
everybody else needing it has to wait until you decide whether to
commit on rollback.

Sequences are for when you need autogenerated keys. They use
consecutive integer blocks nearly everywhere because they are easy to
code, play well with btree indexes, correlate well with insertion
times, but they give up the "no hole" approach to improve performance.
They even can return values unordered in different sessions (
sequences acquire, and burn,  blocks in a locking way, when you need
high concurrency you make them return big blocks, but them values from
different sessions can be delivered out of order ).

If you need correlative numbers, byte the bullet and code it, trying
to do it with sequences will probably end with an approach which will
fail in some corner cases and be slower than just coding it with a
single row table ( just remember to check it, so you do not have the
fun which ensues in oracle when someone puts two rows in dual in the
old days ). All the queries you have posted are probably more complex
than a couple procedures to update and read a table, even using eval
to simulate named sequences if you want ( just remember to always
pre-increment before reading, there is a reason everybody does it that
way ).

As a remark, in Spain bill numbers need to be gapless increasing. I
have done it with a sequence ( with cache 1, so I doubt it is much
more performant than a single row table, as it has a backing element
which needs to be saved ), and just used another process which swept
the values and filled the gap a posteriori ( there is a way to fill a
gap, has it legal uses, you can use it for that as long as you do not
have too many, basically insert cancelled bills in the gaps ). I
probably would do it with the one-row table now for simplicity, I
doubt I gained enough performance to justify the 20-something perl
lines plus the crontab entry to use sequences. As beard turns grey I
apreciate more the simpler ways to do things.

Francisco Olarte.



pgsql-general by date:

Previous
From: Adrian Klaver
Date:
Subject: Re: Out Of Memory
Next
From: Marc Millas
Date:
Subject: Re: postgis