A instrução INSERT ON CONFLICT oferece semântica atômica de upsert: insere uma linha se não houver conflito ou atualiza (ou ignora) a linha existente caso detecte uma chave primária duplicada.
Use esta instrução ao importar dados diretamente com SQL. Para gravações via Data Integration e Flink, consulte Casos de uso.
Conceitos principais
A instrução suporta três modos de resolução de conflitos:
|
Modo |
Cláusula SQL |
Comportamento em caso de chave primária duplicada |
|
InsertOrIgnore |
|
Descarta a linha recebida; a linha existente permanece inalterada |
|
InsertOrUpdate |
|
Atualiza apenas as colunas listadas; as demais mantêm seus valores atuais |
|
InsertOrReplace |
|
Sobrescreve toda a linha; colunas ausentes recebem |
Escolha um modo:
Use InsertOrIgnore quando a primeira gravação deve prevalecer e você não deseja sobrescrever dados existentes.
Use InsertOrUpdate se forem necessárias atualizações seletivas de colunas, preservando aquelas não especificadas.
Use InsertOrReplace para substituição completa da linha, definindo explicitamente as colunas ausentes como
null.
Casos de uso
A instrução INSERT ON CONFLICT aplica-se à importação de dados por meio de instruções SQL.
Data Integration (DataWorks)
O Data Integration possui um recurso nativo de INSERT ON CONFLICT. Configure a Write Conflict Policy no Hologres Writer:
Ignore — equivalente a InsertOrIgnore
Replace — equivalente a InsertOrReplace
Essa política vale tanto para sincronização offline quanto em tempo real. Para atualizar dados durante a sincronização, a tabela do Hologres precisa ter uma chave primária.
Flink
A write conflict policy padrão para gravações via Flink é InsertOrIgnore. Esse comportamento exige uma chave primária na tabela de destino e mantém a primeira entrada ao encontrar duplicatas. Ao usar a sintaxe ctas, o padrão passa a ser InsertOrUpdate.
Sintaxe
INSERT INTO <table_name> [ AS <alias> ] [ ( <column_name> [, ...] ) ]
{ VALUES ( { <expression> } [, ...] ) [, ...] | <query> }
[ ON CONFLICT [ conflict_target ] conflict_action ]
-- conflict_target
ON CONSTRAINT constraint_name
-- conflict_action
DO NOTHING
DO UPDATE SET { <column_name> = { <expression> } |
( <column_name> [, ...] ) = ( { <expression> } [, ...] ) |
} [, ...]
[ WHERE condition ]
Sobre excluded:
O termo excluded é um alias de tabela virtual que referencia a linha proposta para inserção — ou seja, a linha que originou o conflito. Não se trata de um alias para a tabela de origem. Use excluded.<column_name> para referenciar uma coluna específica da linha recebida ou ROW(excluded.*) para acessar todas as colunas na ordem definida no DDL.
Parâmetros:
|
Parâmetro |
Descrição |
|
|
Tabela de destino |
|
|
Nome alternativo para a tabela de destino |
|
|
Coluna alvo na tabela de destino |
|
|
InsertOrIgnore — ignora a inserção quando existe uma chave primária duplicada |
|
|
InsertOrUpdate ou InsertOrReplace — atualiza a linha existente quando há uma chave primária duplicada |
|
|
Valor a ser gravado. Use |
Funcionamento
A instrução INSERT ON CONFLICT segue o mesmo caminho interno de execução do UPDATE. O desempenho da atualização varia conforme o formato de armazenamento da tabela.
Tabelas orientadas a colunas
Tabelas sem chave primária oferecem o maior throughput de gravação. Para tabelas com chave primária:
InsertOrIgnore > InsertOrReplace >= InsertOrUpdate (full row) > InsertOrUpdate (partial column)
Tabelas orientadas a linhas
InsertOrReplace = InsertOrUpdate (full row) >= InsertOrUpdate (partial column) >= InsertOrIgnore
Para obter o melhor desempenho em tabelas orientadas a linhas, mantenha a ordem das colunas na cláusula DO UPDATE SET consistente com a cláusula INSERT e execute uma atualização de linha completa:
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Colunas com valores padrão não são atualizadas peloDO UPDATE, o que reduz o desempenho. Para implementar InsertOrReplace via SQL, passenullexplicitamente na listaVALUES. Ferramentas como Flink e Data Integration adicionamnullautomaticamente para colunas ausentes.
Limitações
A cláusula
ON CONFLICTdeve referenciar todas as colunas da chave primária.-
Quando o Hologres High-QPS Engine (HQE) executa
INSERT ON CONFLICT, a ordem das operações não é garantida — as semânticas de manter a primeira ou a última entrada não têm suporte. O comportamento adotado é manter qualquer uma. Para impor a retenção da última entrada em linhas duplicadas na origem, defina:set hg_experimental_affect_row_multiple_times_keep_last = on; -
Os dados de origem não devem conter linhas duplicadas. A semântica do PostgreSQL exige que cada linha na lista
VALUESou na consulta de source seja única. Se a source contiver duplicatas (por exemplo, devido a uma subconsultaSELECTque retorna duas linhas com a mesma chave primária), a instrução falhará. Para evitar isso, remova as duplicatas na source antes da cláusulaON CONFLICT:-- Deduplicate the source with a subquery before upserting INSERT INTO target_table (a, b, c) SELECT a, MAX(b), MAX(c) FROM source_table GROUP BY a ON CONFLICT (a) DO UPDATE SET (a, b, c) = ROW(excluded.*);
Exemplos
Configurar a tabela de teste
BEGIN;
CREATE TABLE test1 (
a int NOT NULL PRIMARY KEY,
b int,
c int
);
COMMIT;
INSERT INTO test1 VALUES (1, 2, 3);
Os exemplos abaixo são independentes entre si. Cada um parte do estado inicial apresentado acima.
InsertOrIgnore — ignorar em caso de conflito
Se existir uma chave primária duplicada, a linha recebida será descartada.
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO NOTHING;
Resultado:
a | b | c
1 | 2 | 3 -- unchanged
InsertOrUpdate — atualizar colunas específicas
Somente as colunas listadas em SET são atualizadas. As colunas não listadas mantêm seus valores atuais.
-- Partial-column update: only b is updated, c keeps its value
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b;
Resultado:
a | b | c
1 | 1 | 3 -- c unchanged
InsertOrUpdate — atualização de linha completa
Duas formas equivalentes:
-- Method 1: list all columns explicitly
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b, c = excluded.c;
-- Method 2: use ROW(excluded.*) shorthand
INSERT INTO test1 (a, b, c) VALUES (1, 1, 1)
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Resultado:
a | b | c
1 | 1 | 1
InsertOrReplace — sobrescrever com null para colunas ausentes
Para substituir uma linha inteira e preencher colunas ausentes com null, passe null explicitamente na lista VALUES.
INSERT INTO test1 (a, b, c) VALUES (1, 1, null)
ON CONFLICT (a)
DO UPDATE SET b = excluded.b, c = excluded.c;
Resultado:
a | b | c
1 | 1 | \N
Upsert a partir de outra tabela
-- Prepare source table
CREATE TABLE test2 (
d int NOT NULL PRIMARY KEY,
e int,
f int
);
INSERT INTO test2 VALUES (1, 5, 6);
-- Replace rows in test1 with matching rows from test2
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Resultado:
a | b | c
1 | 5 | 6
Para remapear colunas (por exemplo, test2.e atualiza test1.c e test2.f atualiza test1.b):
INSERT INTO test1 (a, b, c)
SELECT d, e, f FROM test2
ON CONFLICT (a)
DO UPDATE SET (a, c, b) = ROW(excluded.*);
Resultado:
a | b | c
1 | 6 | 5
Solução de problemas
Erro: duplicate key value violates unique constraint / Update row with Key multiple times
Sintomas:
duplicate key value violates unique constraint
-- or --
Update row with Key (xxx)=(yyy) multiple times
Causa: Os dados de source contêm linhas duplicadas. O exemplo a seguir reproduz o erro:
-- This fails: the source contains (1, 2, 3) twice
INSERT INTO test1 VALUES (1, 2, 3), (1, 2, 3)
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
-- ERROR: internal error or constraint violation
Estado da tabela após o erro: test1 permanece inalterada.
Correção: Defina o sinalizador keep-last para resolver automaticamente as linhas duplicadas na source:
set hg_experimental_affect_row_multiple_times_keep_last = on;
Alternativamente, remova as duplicatas na source antes de executar o upsert (consulte Limitações).
Erro: chave duplicada causada por TTL expirado
Causa: Uma tabela de source tem um tempo de vida (TTL) configurado. Após a expiração do TTL, linhas obsoletas podem não ser limpas imediatamente, deixando chaves primárias duplicadas na source.
Correção: A partir do Hologres V1.3.23, use o comando a seguir para remover linhas com chave primária duplicada causadas por TTL expirado. A política padrão é keep-last. Este comando está disponível apenas no Hologres V1.3.23 e versões posteriores — se sua instância for de uma versão anterior, faça o upgrade primeiro.
Em princípio, chaves primárias não devem ser duplicadas. Este comando limpa apenas PKs duplicadas causadas por TTL expirado, e não duplicações gerais de PK.
call public.hg_remove_duplicated_pk('<schema>.<table_name>');
Exemplo:
BEGIN;
CREATE TABLE tbl_1 (a int NOT NULL PRIMARY KEY, b int, c int);
CREATE TABLE tbl_2 (d int NOT NULL PRIMARY KEY, e int, f int);
CALL set_table_property('tbl_2', 'time_to_live_in_seconds', '300');
COMMIT;
INSERT INTO tbl_1 VALUES (1, 1, 1), (2, 3, 4);
INSERT INTO tbl_2 VALUES (1, 5, 6);
-- After 300 seconds, insert a row with the same primary key into tbl_2.
INSERT INTO tbl_2 VALUES (1, 3, 6);
-- This fails: tbl_2 now has duplicate primary keys caused by TTL expiry.
INSERT INTO tbl_1 (a, b, c)
SELECT d, e, f FROM tbl_2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
-- ERROR: internal error: Duplicate keys detected when building hash table.
-- Clean up duplicate primary keys in tbl_2, then retry.
call public.hg_remove_duplicated_pk('tbl_2');
-- The import now succeeds.
INSERT INTO tbl_1 (a, b, c)
SELECT d, e, f FROM tbl_2
ON CONFLICT (a)
DO UPDATE SET (a, b, c) = ROW(excluded.*);
Erro: falta de memória (OOM)
Sintoma:
Total memory used by all existing queries exceeded memory limitation
Causa: A instância não tem memória suficiente para uma tarefa de gravação de grande volume.
Correção:
Use o Serverless Computing (Hologres V2.1.17+) para descarregar a tarefa em recursos serverless, reduzindo o risco de OOM sem reservar capacidade extra da instância.
Siga as etapas descritas em Solucionar erros comuns de OOM.
Próximos passos
UPDATE — compreenda o mecanismo subjacente de atualização
Visão geral do Serverless Computing — descarregue grandes tarefas de gravação em recursos serverless (Hologres V2.1.17+)
Hologres Writer — configure a política de conflito de gravação no Data Integration