Eu tenho uma tabela simples como abaixo no PostgreSQL 13:
table name: newtable1
field type
----- ----
Seq bigserial
code varchar
Seq
é a chave primária (incremento automático)
Code
é um índice de chave único
Insert Into newtable (Code) Values ('001') On Conflict(Code) Do Nothing --> Seq value is 1
Insert Into newtable (Code) Values ('001') On Conflict(Code) Do Nothing
Insert Into newtable (Code) Values ('001') On Conflict(Code) Do Nothing
Insert Into newtable (Code) Values ('002') On Conflict(Code) Do Nothing --> Seq value is 4
Pergunta
Por que o valor Seq continua aumentando?
Existe alguma maneira de aumentar apenas o valor Seq se ele for inserido com sucesso?
O motivo é que
DEFAULT
os valores (e gatilhos e qualquer outra coisa que possa alterar os valores das linhas) são aplicados antes da verificação de duplicatas (tentando inserir tuplas de índice). Eserial
os números são projetados para se defender contra condições de corrida sob carga simultânea. O subjacenteSEQUENCE
não "retoma" os números depois de incrementado. Existem outros cenários que queimariam números de série. Portanto, lacunas nos números de série são esperadas. Contanto que você não queime números em uma velocidade gigantesca, isso não deve ser um problema.Não sem (mais ou menos) comprometer seriamente o desempenho, como usar
SERIALIZABLE
o isolamento de transações ou estratégias de bloqueio manual. Essa é a razão pela qual aON CONFLICT
cláusula ("UPSERT") existe em primeiro lugar.Se você não tiver gravações simultâneas na mesma tabela (você tem certeza?), essa consulta alternativa evitaria a gravação de números de série:
É um pouco mais caro no caso não conflitante, pois primeiro verifica a existência no índice e, em seguida, insere a nova linha na tabela e nos índices. Mas um pouco mais rápido para casos conflitantes. Há uma pequena janela entre a verificação e a gravação, onde as condições de corrida podem causar problemas sob carga de gravação simultânea. É quando usamos um UPSERT.
Relacionado: