INSERT ON CONFLICT oferece semântica de upsert atômica: insere uma linha caso não haja conflito, ou atualiza (ou ignora) a linha existente quando uma chave primária duplicada é detectada.
Use esta instrução ao importar dados diretamente via SQL. Para escrita com 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 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 |
|
Substitui a linha inteira; colunas ausentes tornam-se |
Escolha um modo:
Use InsertOrIgnore quando a primeira escrita deve prevalecer e você nunca quer sobrescrever dados existentes.
Use InsertOrUpdate quando precisar atualizar colunas selecionadas e as colunas não listadas devem ser preservadas.
Use InsertOrReplace para substituição completa da linha, com colunas ausentes definidas explicitamente como
null.
Casos de uso
INSERT ON CONFLICT é aplicável quando você importa dados usando 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
A política se aplica tanto à sincronização offline quanto à sincronização em tempo real. Para atualizar dados durante a sincronização, a tabela Hologres deve ter uma chave primária.
Flink
A write conflict policy padrão para escrita com Flink é InsertOrIgnore. Essa configuração exige uma chave primária na tabela de destino e mantém o primeiro registro quando um duplicado é encontrado. Ao usar a sintaxe ctas, o padrão muda para 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:
excluded é um alias de tabela virtual que referencia a linha proposta para inserção — a linha que gerou o conflito. Não é um alias para a tabela de origem. Use excluded.<column_name> para referenciar uma coluna específica da linha recebida, ou ROW(excluded.*) para referenciar todas as colunas na ordem definida pelo DDL.
Parâmetros:
|
Parâmetro |
Descrição |
|
|
A tabela de destino |
|
|
Um nome alternativo para a tabela de destino |
|
|
Uma coluna de destino na tabela de destino |
|
|
InsertOrIgnore — ignora a inserção quando existe uma chave primária duplicada |
|
|
InsertOrUpdate ou InsertOrReplace — atualiza a linha existente quando existe uma chave primária duplicada |
|
|
O valor a ser gravado. Use |
Como funciona
INSERT ON CONFLICT executa o mesmo caminho interno que UPDATE. O desempenho das atualizações depende do formato de armazenamento da tabela.
Tabelas orientadas a colunas
Tabelas sem chave primária oferecem o maior throughput de escrita. 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 faça 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 de 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 keep-first e keep-last não são suportadas. O comportamento é keep-any. Para forçar keep-last 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 origem seja única. Se a origem contiver duplicatas (por exemplo, de uma subconsultaSELECTque retorna duas linhas com a mesma chave primária), a instrução falha. Para evitar isso, elimine as duplicatas na origem 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 a seguir são independentes entre si. Cada um parte do estado inicial acima.
InsertOrIgnore — ignorar em caso de conflito
Quando existe uma chave primária duplicada, a linha recebida é 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 demais 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 origem 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 flag keep-last para resolver linhas duplicadas na origem automaticamente:
set hg_experimental_affect_row_multiple_times_keep_last = on;
Como alternativa, elimine as duplicatas na origem antes do upsert (consulte Limitações).
Erro: chave duplicada causada por TTL expirado
Causa: Uma tabela de origem possui time to live (TTL) configurado. Após a expiração do TTL, linhas obsoletas podem não ser removidas imediatamente, deixando chaves primárias duplicadas na origem.
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 remove apenas PKs duplicadas causadas por TTL expirado, 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 possui memória suficiente para uma tarefa de escrita de grande volume.
Correção:
Use Serverless Computing (Hologres V2.1.17+) para delegar a tarefa a recursos serverless, reduzindo o risco de OOM sem reservar capacidade adicional na instância.
Siga as etapas descritas em Troubleshoot common OOM errors.
Próximas etapas
UPDATE — entenda o mecanismo de atualização subjacente
Serverless Computing overview — delegue grandes tarefas de escrita a recursos serverless (Hologres V2.1.17+)
Hologres Writer — configure a política de conflito de escrita no Data Integration