1. O que é UPSERT?
Visão geral
“UPSERT” refere‑se a um recurso de banco de dados que combina as operações “INSERT” e “UPDATE”. Em outras palavras, se os dados ainda não existirem, eles são inseridos; se os mesmos dados já existirem, eles são atualizados. Ao usar esse recurso, você pode executar operações eficientes enquanto mantém a consistência dos dados.
No MySQL, essa funcionalidade é implementada usando a sintaxe INSERT ... ON DUPLICATE KEY UPDATE. Esse recurso permite evitar erros de chave duplicada e atualizar registros existentes mesmo quando ocorrem chaves duplicadas.
Casos de uso
- Sistemas de gerenciamento de clientes: Adicionar novos dados de cliente se eles não existirem e atualizar as informações do cliente existente quando houver alterações.
- Gerenciamento de estoque de produtos: Inserir novos produtos enquanto atualiza a quantidade em estoque dos produtos já existentes.
Vantagens do UPSERT no MySQL
- Evita erros de chave duplicada
- Simplifica consultas SQL
- Mantém a integridade dos dados
2. Uso básico de UPSERT no MySQL
No MySQL, as operações de UPSERT são realizadas usando a sintaxe INSERT ... ON DUPLICATE KEY UPDATE. Com essa sintaxe, se ocorrer uma chave duplicada, você pode atualizar parte ou todo o dado existente em vez de inserir novos dados.
Sintaxe básica
INSERT INTO table_name (column1, column2)
VALUES (value1, value2)
ON DUPLICATE KEY UPDATE
column1 = value1, column2 = value2;
Explicação:
- Use
INSERT INTOpara inserir dados. - Se os dados que estão sendo inseridos já existirem na tabela, a cláusula
ON DUPLICATE KEY UPDATEé executada e os dados existentes são atualizados.
Exemplo:
INSERT INTO users (user_id, name)
VALUES (1, 'Taro Tanaka')
ON DUPLICATE KEY UPDATE
name = 'Taro Tanaka';
No exemplo acima, se já existir um usuário com user_id igual a 1, o campo name será atualizado para ‘Taro Tanaka’. Se o usuário não existir, um novo registro será inserido.

3. Sintaxe SQL detalhada e exemplos de UPSERT
Atualizando múltiplas colunas
Ao usar UPSERT, há situações em que você pode querer atualizar apenas colunas específicas. Nesses casos, basta especificar apenas as colunas necessárias na cláusula ON DUPLICATE KEY UPDATE.
INSERT INTO products (product_id, name, price)
VALUES (100, 'Laptop', 50000)
ON DUPLICATE KEY UPDATE
price = VALUES(price);
Neste exemplo, se já existir um produto com product_id 100, apenas a coluna price será atualizada, enquanto as demais colunas (como name) permanecerão inalteradas.
4. Diferenças em relação a outros bancos de dados
Bancos de dados diferentes do MySQL também oferecem funcionalidade semelhante. Por exemplo, PostgreSQL e SQLite utilizam INSERT ... ON CONFLICT ou instruções MERGE para obter comportamento de UPSERT.
Exemplo no PostgreSQL
INSERT INTO users (user_id, name)
VALUES (1, 'Taro Tanaka')
ON CONFLICT (user_id) DO UPDATE SET
name = 'Taro Tanaka';
No PostgreSQL e no SQLite, a cláusula ON CONFLICT é usada para controlar o comportamento quando ocorre um erro de chave duplicada. Em contraste, o MySQL utiliza a cláusula ON DUPLICATE KEY UPDATE.
Características específicas do MySQL
- O MySQL usa
INSERT ... ON DUPLICATE KEY UPDATE; como a sintaxe difere de outros bancos de dados, é necessário ter cuidado especial ao migrar entre sistemas.
5. Técnicas avançadas de UPSERT
UPSERT em lote (processamento em massa de múltiplos registros)
UPSERT pode ser executado não apenas para um único registro, mas também para vários registros de uma só vez. Isso melhora significativamente a eficiência das operações no banco de dados.
INSERT INTO products (product_id, name, price)
VALUES
(100, 'Laptop', 50000),
(101, 'Smartphone', 30000)
ON DUPLICATE KEY UPDATE
price = VALUES(price);
Neste exemplo, vários registros de produtos são inseridos de uma só vez. Se existirem chaves duplicadas, apenas o campo price dos registros correspondentes será atualizado.
Usando procedures armazenadas para UPSERT
Para otimizar o processamento UPSERT, você também pode usar procedimentos armazenados. Isso permite criar lógica reutilizável dentro do banco de dados, melhorando tanto a legibilidade quanto a manutenibilidade do seu código.
6. Armadilhas Comuns e Considerações Importantes
Transações e Deadlocks
Ao usar UPSERT—especialmente com grandes volumes de dados—deadlocks podem ocorrer. Se o nível de isolamento de transação do MySQL estiver definido como REPEATABLE READ, bloqueios de gap são mais propensos a acontecer.
Evitando Bloqueios de Gap
- Você pode reduzir a probabilidade de deadlocks alterando o nível de isolamento de transação para
READ COMMITTED. - Se necessário, considere dividir uma grande operação UPSERT em lotes menores e executar múltiplas consultas em vez de uma única declaração grande.
7. Conclusão
O recurso UPSERT do MySQL é extremamente útil para simplificar a inserção e atualização de dados, evitando erros de chaves duplicadas. No entanto, a implementação do UPSERT requer consideração cuidadosa de deadlocks potenciais e configurações de transação. Quando usado corretamente, ele permite operações de banco de dados mais simples e eficientes.


