Fundo
Esse problema está relacionado a ignorar inserções duplicadas usando o PostgreSQL 9.2 ou superior. A razão pela qual eu pergunto é por causa deste código:
-- Ignores duplicates.
INSERT INTO
db_table (tbl_column_1, tbl_column_2)
VALUES (
SELECT
unnseted_column,
param_association
FROM
unnest( param_array_ids ) AS unnested_column
);
O código é livre de verificações de valores existentes. (Nesta situação específica, o usuário não se importa com erros de inserção de duplicatas -- a inserção deve "simplesmente funcionar".) Adicionar código nessa situação para testar explicitamente duplicatas traz complicações.
Problema
No PostgreSQL, encontrei algumas maneiras de ignorar inserções duplicadas.
Ignorar duplicatas #1
Crie uma transação que detecte violações de restrição exclusivas, sem realizar nenhuma ação:
BEGIN
INSERT INTO db_table (tbl_column) VALUES (v_tbl_column);
EXCEPTION WHEN unique_violation THEN
-- Ignore duplicate inserts.
END;
Ignorar duplicatas #2
Crie uma regra para ignorar duplicatas em uma determinada tabela:
CREATE OR REPLACE RULE db_table_ignore_duplicate_inserts AS
ON INSERT TO db_table
WHERE (EXISTS ( SELECT 1
FROM db_table
WHERE db_table.tbl_column = NEW.tbl_column)) DO INSTEAD NOTHING;
Perguntas
Minhas perguntas são principalmente acadêmicas:
- Qual método é mais eficiente?
- Qual método é mais sustentável e por quê?
- Qual é a maneira padrão de ignorar erros de duplicação de inserção com o PostgreSQL?
- Existe uma maneira tecnicamente mais eficiente de ignorar inserções duplicadas; Se assim for, o que é?
Obrigada!
Como mencionam as respostas da outra pergunta (da qual esta é considerada uma duplicata), existe (desde a versão 9.5) uma
UPSERT
funcionalidade nativa. Para versões mais antigas, continue lendo :)Eu configurei um teste para verificar as opções. Incluirei o código abaixo, que pode ser executado em
psql
uma caixa linux/Unix (simplesmente porque, para maior clareza nos resultados, canalizei a saída dos comandos de instalação para/dev/null
- em uma caixa do Windows, pode-se escolher um log arquivo em vez disso).Tentei tornar diferentes resultados comparáveis usando mais de um (ou seja, 100)
INSERT
por tipo, executado a partir de um loop dentro de umplpgsql
procedimento armazenado. Além disso, antes de cada execução, a tabela é redefinida truncando e reinserindo os dados originais.Verificando algumas execuções de teste, parece que usar a regra e adicionar explicitamente
WHERE NOT EXISTS
aINSERT
instrução gasta tempo semelhante, enquanto capturar uma exceção leva muito mais tempo para ser concluído.O último não é tão surpreendente :
Pessoalmente, devido à legibilidade e manutenção, prefiro adicionar o
WHERE NOT EXISTS
bit aosINSERT
próprios s. Assim como com os gatilhos (que também podem ser testados aqui), a depuração (ou simplesmente oINSERT
comportamento de rastreamento) é mais complicado com as regras presentes.E o código que usei (fique à vontade para apontar equívocos ou outros problemas):