POSTGRES - evita incremento serial com ON CONFLICT DO NOTHING [duplicar]

Sep 03 2020

duplicata desta questão

Digamos que eu tenha as seguintes coisas da tabela. Quero nomes exclusivos na tabela para que não haja duplicatas. O processo que insere algo não deve precisar verificar se algo com esse nome já existe.

CREATE TABLE things(
    id SMALLSERIAL PRIMARY KEY,
    name varchar UNIQUE
);

Quando eu insiro valores como este, funciona. Se 'mesa' já estiver nas coisas, não será inserido.

INSERT INTO things (name)
VALUES ('desk')
ON CONFLICT DO NOTHING;

Tho único problema é ON CONFLICT DO NOTHING não faz realmente nada. Ele ainda incrementa a sequência para o campo id.

Se isso acontecer com muita freqüência, a sequência de id eventualmente ficará muito grande para o tipo de campo.

Tem algum jeito de prevenir que isso aconteça?

Respostas

4 GMB Sep 03 2020 at 16:08

Usando insert ... on conflict, você não pode evitar o serialincremento automático em conflitos. Postgres (assim como outros bancos de dados) não garante que as séries sejam sequenciais, conforme explicado na documentação :

Porque smallserial, seriale bigserialsão implementados usando sequências, pode haver "buracos" ou lacunas na sequência de valores que aparecem na coluna, mesmo que nenhuma linha seja excluída. Um valor alocado da sequência ainda é "usado", mesmo se uma linha que contém esse valor nunca for inserida com êxito na coluna da tabela. Isso pode acontecer, por exemplo, se a transação de inserção for revertida.

Se você estiver executando muitos desses insertacabamentos em conflito, uma maneira de limitar o bleading seria alterar a sintaxe para not exists:

insert into things (name)
select name
from (values ('desk')) v(name)
where not exists (select 1 from things t1 where t1.name = v.name)

Observe que isso ainda não garante que as publicações em série serão sequenciais (consulte a citação acima da documentação).