This is completely normal.
When you create a field in a table of type SERIAL
or BIGSERIAL
, one SEQUENCE
is created implicitly to make the auto-increment control of this field.
Fields of the type SERIAL
and BIGSERIAL
have a value DEFAULT
which consists of the function call return nextval()
.
In a real scenario, several isolated transactions may be calling nextval()
for the same SEQUENCE
, simultaneously, one will be effective and another will be discarded.
EVEN the discarded transactions (which suffered ROLLBACK
), do not decrease the SEQUENCE
, causing that sequential number to be lost forever.
The gaps
that you are observing, are actually, transactions that called nextval()
, however, they suffered ROLLBACK
at some point.
To SEQUENCE
is never decremented, not even if there was a ROLLBACK
in the transaction that incremented it (and doing this decrease manually is not a good idea!).
According to the documentation of PostgreSQL
, in the section on Manipulação de Sequências
, there is an explanation about this behavior in the function reference nextval()
, look at you:
nextval
Advance the Sequence Object to its next value and Return that value.
This is done atomically: Even if Multiple Sessions execute
nextval
concurrently, each will Safely receive a distinct Quence
value.
[...]
Important
To avoid blocking Concurrent transactions that obtain Numbers from the
same Quence, the 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.
Have you thought about reevaluating the real need to have a sequence field without gaps ?
Consider the following:
CREATE TABLE tb_historico
(
id BIGSERIAL PRIMARY KEY,
valor INTEGER,
datahora TIMESTAMP DEFAULT NOW()
);
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); COMMIT;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); COMMIT;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); COMMIT;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); COMMIT;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); ROLLBACK;
BEGIN; INSERT INTO tb_historico ( valor ) VALUES ( 100 ); COMMIT;
You can use the function row_number()
to list your records, see only:
SELECT
row_number() OVER (ORDER BY id) AS id_gapless,
id,
valor,
datahora
FROM
tb_historico;
Exit:
| id_gapless | id | valor | datahora |
|------------|----|-------|-----------------------------|
| 1 | 3 | 100 | 2018-07-04T19:07:11.651281Z |
| 2 | 5 | 100 | 2018-07-04T19:07:11.654413Z |
| 3 | 7 | 100 | 2018-07-04T19:07:11.657451Z |
| 4 | 9 | 100 | 2018-07-04T19:07:11.660584Z |
| 5 | 11 | 100 | 2018-07-04T19:07:11.66475Z |
See working on Ideone.com
It wasn’t another attempt by Insert that went wrong, was it? when a rollback occurs in the transaction, Quence does not return the number that was generated in the transaction
– Rovann Linhalis
I tested several times, dropped the table and ran the function, just to reset the autoincrement.
– D. Watson