DELETE vs TRUNCATE vs DROP: Diferenças, reversão e quando usar cada um
Todos os três comandos removem algo, mas removem coisas diferentes de maneiras diferentes. Aqui está o que cada um faz, o que pode ser desfeito e como as regras mudam entre os bancos de dados.
- DELETE remove linhas, opcionalmente filtradas com WHERE. A mesa fica.
- TRUNCATE remove todas as linhas rapidamente. A estrutura da tabela permanece.
- DROP remove toda a tabela: dados, estrutura, índices e gatilhos.
- Rollback, gatilhos e redefinição de identidade se comportam de maneira diferente em cada banco de dados, portanto verifique o seu.
Um testador deseja limpar uma tabela intermediária antes de uma nova execução de teste. Deveria ser DELETE, TRUNCATE ou DROP? A escolha errada pode significar um trabalho lento, uma mesa faltando ou, na produção, uma tarde muito ruim.
Executamos os exemplos DELETE e DROP abaixo no SQLite 3.50, e as saídas vêm dessa execução. SQLite não tem comando TRUNCATE, então as notas TRUNCATE são baseadas na documentação oficial do PostgreSQL, MySQL e SQL Server, e não em nosso próprio teste.
A resposta curta
- Precisa remover algumas linhas? Utilize
DELETE ... WHERE. - Precisa esvaziar uma mesa, mas mantê-la? Use
TRUNCATE, onde for suportado. - Precisa que a mesa desapareça para sempre? Utilize
DROP TABLE.
DELETE: remove linhas
DELETE é um comando de alteração de dados (DML). Ele remove uma linha por vez, dispara gatilhos em nível de linha e pode ser filtrado. Montamos uma pequena tabela com um gatilho de auditoria:
CREATE TABLE logs (id INTEGER PRIMARY KEY AUTOINCREMENT, level TEXT);
INSERT INTO logs (level) VALUES ('INFO'),('ERROR'),('INFO'),('DEBUG');
CREATE TABLE audit (msg TEXT);
CREATE TRIGGER logs_delete AFTER DELETE ON logs
BEGIN INSERT INTO audit VALUES ('deleted ' || OLD.id); END;
DELETE FROM logs WHERE level = 'DEBUG';
SELECT id, level FROM logs; -- (1,'INFO'), (2,'ERROR'), (3,'INFO')
SELECT * FROM audit; -- 'deleted 4'
Apenas a linha correspondente foi e o gatilho a registrou. A execução de DELETE FROM logs sem uma cláusula WHERE removeu as outras três linhas e a tabela de auditoria manteve quatro entradas, uma por linha excluída.
DELETE não redefine contadores de incremento automático. Depois de esvaziar a tabela, nossa próxima inserção recebeu id 5, e não 1. No SQLite isso ocorre por causa de AUTOINCREMENT. As colunas de identidade do MySQL InnoDB e do SQL Server também continuam de onde estavam após um DELETE.
Dica: Antes de qualquer DELETE com uma cláusula WHERE, execute primeiro a mesma cláusula de SELECT COUNT(*). Se a contagem te surpreender, pare. Leia nosso guia para valores SQL NULL para as armadilhas que NULL cria em uma cláusula WHERE.
TRUNCATE: esvazia a tabela
TRUNCATE TABLE logs; remove todas as linhas de uma vez. Não pode aceitar uma cláusula WHERE. Em vez de excluir as linhas uma por uma, o banco de dados normalmente libera as páginas de dados da tabela, por isso é muito mais rápido em tabelas grandes.
Ao rodarmos no SQLite, obtivemos um erro de sintaxe, pois o SQLite não possui o comando:
TRUNCATE TABLE logs;
-- near "TRUNCATE": syntax error
No SQLite, use DELETE FROM logs; sem cláusula WHERE. A documentação do SQLite descreve uma “otimização truncada” que torna isso rápido quando a tabela não possui gatilhos. Nossa tabela tinha um gatilho, então a exclusão era executada linha por linha e disparada para cada linha.
Em bancos de dados que suportam TRUNCATE, pela sua documentação:
- Normalmente não dispara gatilhos DELETE em nível de linha.
- Geralmente redefine os contadores de identidade ou de incremento automático, por exemplo, no MySQL e no SQL Server. No PostgreSQL você adiciona
RESTART IDENTITY. - Precisa de permissões mais fortes que DELETE na maioria dos sistemas.
DROP: remova a própria tabela
DROP TABLE é um comando de esquema (DDL). Remove os dados, a definição da tabela, seus índices, gatilhos e restrições. Qualquer coisa que se refira à tabela, como visualizações ou chaves estrangeiras, também será afetada.
DROP TABLE logs;
SELECT * FROM logs;
-- no such table: logs
DROP TABLE IF EXISTS logs; -- no error, even though it is gone
IF EXISTS é útil em scripts de configuração que podem ser executados mais de uma vez. As visualizações em uma tabela eliminada podem falhar, como mostramos em explicações das visualizações SQL.
Tabela de comparação
| Recurso | EXCLUIR | TRUNCAR | QUEDA |
|---|---|---|---|
| Remove | Algumas ou todas as linhas | Todas as linhas | Tabela e linhas |
| Cláusula WHERE | Sim | Não | Não |
| Tipo de comando | DML | DDL (normalmente) | DDL |
| Linha desencadeia fogo | Sim | Geralmente não | Não |
| Redefine a identidade | Não | Geralmente sim | A mesa desapareceu |
| Velocidade em mesas grandes | Lento | Rápido | Rápido |
| Resta a mesa | Sim | Sim | Não |
Você pode reverter?
É aqui que muitos artigos simplificam demais. A resposta honesta é que depende do banco de dados.
DELETE pode ser revertido dentro de uma transação em qualquer lugar. Nós testamos:
BEGIN;
DELETE FROM logs;
SELECT COUNT(*) FROM logs; -- 0
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 3
DROP também foi revertido no SQLite, que suporta DDL transacional:
BEGIN;
DROP TABLE logs;
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 1 (the table is back)
Para TRUNCATE e DROP em outros bancos de dados, de acordo com sua documentação:
| Banco de dados | TRUNCATE / DROP em uma transação |
|---|---|
| PostgreSQL | Pode ser revertido. DDL é transacional. |
| Servidor SQL | Pode ser revertido dentro de uma transação explícita. |
| MySQL | Causa um commit implícito, portanto não pode ser revertido. |
| Oráculo | Confirma implicitamente. DROP pode ser recuperável da lixeira. |
Portanto, “TRUNCATE nunca pode ser revertido” é errado para PostgreSQL e SQL Server, e “sempre pode ser revertido” é errado para MySQL. Fora de uma transação, nenhuma delas pode ser desfeita sem um backup.
Por que TRUNCATE é rápido
DELETE registra cada linha removida para que a alteração possa ser desfeita e replicada, dispara gatilhos e verifica restrições linha por linha. Em uma tabela com milhões de linhas, isso cria muito trabalho e volume de log. TRUNCATE geralmente desaloca o armazenamento em uma operação, registrando muito menos. Para remover um subconjunto grande em vez de tudo, exclua em lotes para evitar bloqueios longos. Cobrimos os custos de bloqueio e consulta na otimização de consultas SQL.
Chaves estrangeiras e permissões
- Chaves estrangeiras. O SQL Server se recusa a TRUNCAR uma tabela referenciada por uma chave estrangeira. O PostgreSQL também exige que você trunque as tabelas de referência ou use
CASCADE. Em vez disso, um DELETE verifica cada linha em relação às restrições. - Permissões. DELETE precisa de direitos de exclusão. TRUNCATE geralmente precisa de ALTER ou de um direito TRUNCATE dedicado, e DROP precisa de propriedade ou ALTER no esquema.
- Replicação e auditoria. Se outros sistemas dependerem de logs ou gatilhos de alterações em nível de linha, TRUNCATE poderá ignorá-los. Verifique primeiro com quem possui esses sistemas.
Qual usar
| Situação | Usar |
|---|---|
| Remover os pedidos cancelados de um cliente | EXCLUIR com WHERE |
| Redefinir uma tabela intermediária antes de cada execução de teste | TRUNCATE (ou DELETE no SQLite) |
| Mantenha os gatilhos de auditoria funcionando | EXCLUIR |
| Remover uma tabela que não está mais no design | DROP em uma migração revisada |
| Limpe milhões de linhas antigas, mas mantenha as recentes | EXCLUIR em lotes ou particionar e descartar partições antigas |
Para dados de teste, TRUNCATE é popular porque redefine IDs, o que torna os testes repetíveis. Agrupar cada teste em uma transação que é revertida é outra opção, explicada em Transações SQL e ACID.
Lista de verificação de segurança
- Confirme a qual banco de dados e ambiente você está conectado.
- Execute a cláusula WHERE como um SELECT primeiro.
- Envolva a alteração em uma transação onde seu banco de dados a suporte.
- Tenha um backup recente e testado antes de TRUNCATE ou DROP em produção.
- Coloque instruções DROP em scripts de migração revisados, nunca em consoles ad-hoc.
- Verifique o que depende de uma tabela, como visualizações, chaves estrangeiras e relatórios, antes de descartá-la.
Excluindo grandes quantidades de dados com segurança
A remoção de milhões de linhas com um DELETE pode bloquear a tabela por um longo tempo, preencher o log de transações e retardar a replicação. Um padrão comum é excluir em pequenos lotes e repetir até não sobrar nada:
-- SQL Server style (not run for this article)
DELETE TOP (5000) FROM logs WHERE created_at < '2026-01-01';
-- PostgreSQL style (not run for this article)
DELETE FROM logs
WHERE id IN (SELECT id FROM logs WHERE created_at < '2026-01-01' LIMIT 5000);
Execute a instrução em um loop, com uma pequena pausa entre os lotes, até que ela relate zero linhas. Cada lote é uma transação pequena, portanto os bloqueios são curtos e outras consultas continuam em execução. Um índice na coluna do filtro, aqui created_at, mantém cada lote rápido.
Para dados que crescem por data, como logs e eventos, o particionamento de tabelas é ainda melhor. Cada mês reside em sua própria partição, e a remoção de dados antigos torna-se uma operação rápida que elimina ou trunca uma partição em vez de excluir linhas uma por uma.
Exclusões suaves
Muitos aplicativos nunca excluem fisicamente registros comerciais. Eles adicionam uma coluna como deleted_at e a definem, e as consultas são filtradas em deleted_at IS NULL. As exclusões suaves facilitam a recuperação e mantêm o histórico para auditorias, mas cada consulta deve lembrar o filtro, o que é um bom trabalho para uma visualização. As restrições exclusivas também precisam de cuidado, porque uma linha excluída de forma reversível ainda mantém seu valor. As leis de privacidade podem exigir a exclusão real de dados pessoais após um período, portanto, as exclusões suaves não substituem uma política de retenção.
Considerações finais
DELETE é a ferramenta precisa e cuidadosa. TRUNCATE é o botão de reinicialização rápida e DROP remove totalmente a tabela. O maior risco é assumir que um banco de dados se comporta como outro, especialmente durante a reversão. Em caso de dúvida, teste primeiro o comando em uma cópia da tabela em seu próprio banco de dados.
Perguntas frequentes
Qual é a principal diferença entre DELETE e TRUNCATE?
DELETE remove linhas uma por uma, suporta WHERE e dispara gatilhos. TRUNCATE remove todas as linhas de uma vez, é muito mais rápido, geralmente ignora os gatilhos de linha e geralmente redefine os contadores de identidade.
O TRUNCATE pode ser revertido?
No PostgreSQL e no SQL Server, sim, dentro de uma transação. No MySQL e no Oracle, ele é confirmado implicitamente, portanto não pode ser revertido.
DELETE redefine o valor do incremento automático?
Não. Após um DELETE, novas linhas continuam a partir do contador anterior. Em nosso teste SQLite, o próximo ID foi 5 após a exclusão de todas as linhas.
O SQLite suporta TRUNCATE?
Não. Use a tabela DELETE FROM sem cláusula WHERE. O SQLite otimiza isso quando a tabela não possui gatilhos.
O que DROP TABLE remove?
Os dados, definição de tabela, índices, gatilhos e restrições. Visualizações e chaves estrangeiras que dependem da tabela podem quebrar ou bloquear a eliminação.
Continue aprendendo
Precisa de ajuda com testes, WordPress ou SEO?
Ajudamos as equipes a fornecer software melhor e a expandir seus sites. Conte-nos no que você está trabalhando e sugeriremos um próximo passo claro.
Mais guias sobre testes, IA e desenvolvimento moderno
Gostou deste artigo? Escolha um tópico e vá direto para nossos tutoriais mais recentes.
Explicação das alucinações de IA: por que os modelos de linguagem inventam as coisas e como reduzi-las
Explicação das alucinações de IA: o que são, por que os modelos de linguagem as produzem, tipos comuns, como reduzi-las com aterramento e instruções…
Leia o artigo →DevOpsVariáveis de ambiente explicadas: arquivos .env, segredos e configuração bem feitos
Variáveis de ambiente explicadas com exemplos de Python que executamos: leitura e configuração, por que cada valor é uma string, arquivos .env, hera…
Leia o artigo →Desenvolvimento de softwareExplicação da limitação de taxa de API: algoritmos, cabeçalhos e tratamento de erros 429
Limitação de taxa de API explicada com uma simulação que executamos: token bucket, janela fixa, janela deslizante, 429 respostas, cabeçalhos de limi…
Leia o artigo →Automação de testesZombando em Python: unittest.mock, patch e os erros que fazem os testes mentirem
Zombaria em Python com unittest.mock, testado: Mock e return_value, side_effect, patch onde um nome é usado, especificação e autospec, zombaria de d…
Leia o artigo →Teste de softwareCobertura de código explicada: cobertura de linha versus filial e o que 100% realmente significa
Cobertura de código explicada com uma execução cobertura.py real: cobertura de linha, ramal e condição, leitura de um relatório, por que 100% de cob…
Leia o artigo →Bancos de dados e SQLDELETE vs TRUNCATE vs DROP em SQL: diferenças, reversão e quando usar cada um
DELETE vs TRUNCATE vs DROP explicado com SQL testado: o que cada um remove, rollback, aciona, redefinição de identidade, velocidade e como PostgreSQ…
Leia o artigo →Bancos de dados e SQLExibições SQL explicadas: crie, use e evite as armadilhas, com exemplos
Visualizações SQL explicadas com consultas que executamos: criação de uma visualização, resultados ao vivo, ocultação de colunas, desempenho, visual…
Leia o artigo →Desenvolvimento de softwareInterface TypeScript vs tipo: diferenças reais, testadas com o compilador
Interface TypeScript versus tipo, verificada com o compilador real: o que ambos podem fazer, o que apenas um pode fazer, mesclagem de declarações, e…
Leia o artigo →Desenvolvimento de softwarePython *args e **kwargs explicados: funções flexíveis com exemplos claros
Python *args e **kwargs explicados com o código que executamos: empacotamento e descompactação, ordem dos parâmetros, argumentos somente de palavras…
Leia o artigo →Desenvolvimento de softwareFunções Python Lambda: sintaxe, usos reais e quando não usá-los
Funções lambda do Python explicadas com o código que executamos: sintaxe, classificação com chave, mapa e filtro, fechamentos, armadilha de ligação …
Leia o artigo →Inteligência artificialO que são agentes de IA? Como eles funcionam, com um loop de agente simples que você pode executar
O que são agentes de IA? Um guia simples para o loop do agente, ferramentas, memória e proteções, com um pequeno loop Python que executamos, riscos …
Leia o artigo →DevOpsMonitoramento versus observabilidade: a verdadeira diferença, com logs, métricas e rastreamentos
Explicação do monitoramento versus observabilidade: falhas conhecidas e desconhecidas, logs, métricas e rastreamentos, um passo a passo do incidente…
Leia o artigo →DevOpsDocker Volumes vs Bind Mounts: persista os dados do contêiner da maneira certa
Volumes Docker versus montagens de ligação explicadas: por que os dados do contêiner desaparecem, volumes nomeados, montagens de ligação, tmpfs, exe…
Leia o artigo →Automação de testesTDD vs BDD: principais diferenças, um recurso criado de ambas as maneiras e quando usar cada um
TDD vs BDD explicado com um recurso de desconto construído em ambos os sentidos: refatoração vermelho-verde com o código que executamos, cenários da…
Leia o artigo →Desenvolvimento de softwareGit merge vs rebase: diferenças, exemplos e quando usar cada um
Git merge vs rebase explicado com saída real do log, uma tabela comparativa, a regra de ouro do rebase e um fluxo de trabalho seguro para equipes.
Leia o artigo →Desenvolvimento de softwareList comprehension em Python: sintaxe, exemplos e quando evitar
List comprehension em Python explicada: sintaxe, filtros, if-else, laços aninhados, tempos medidos e quando um laço for comum é a melhor escolha.
Leia o artigo →Bancos de dados e SQLSQL JOIN explicado com exemplos (Inner, Left, Right, Full)
Entenda os joins SQL passo a passo com tabelas e consultas de exemplo: INNER, LEFT, RIGHT, FULL, CROSS e SELF, além de erros comuns e dicas de desem…
Leia o artigo →