DELETE vs TRUNCATE vs DROP: Diferencias, reversión y cuándo usar cada uno
Los tres comandos eliminan algo, pero eliminan cosas diferentes de diferentes maneras. Esto es lo que hace cada uno, lo que puede deshacer y cómo cambian las reglas entre bases de datos.
- DELETE elimina filas, opcionalmente filtradas con WHERE. La mesa se queda.
- TRUNCATE elimina todas las filas rápidamente. La estructura de la mesa se mantiene.
- DROP elimina toda la tabla: datos, estructura, índices y activadores.
- La reversión, los desencadenantes y el restablecimiento de identidad se comportan de manera diferente en cada base de datos, así que verifique la suya.
Un evaluador quiere borrar una mesa de preparación antes de realizar una nueva ejecución de prueba. ¿Debería ser DELETE, TRUNCATE o DROP? Una elección equivocada puede significar un trabajo lento, una mesa faltante o, en producción, una tarde muy mala.
Ejecutamos los ejemplos DELETE y DROP a continuación en SQLite 3.50, y los resultados provienen de esa ejecución. SQLite no tiene el comando TRUNCATE, por lo que las notas de TRUNCATE se basan en la documentación oficial de PostgreSQL, MySQL y SQL Server en lugar de en nuestra propia prueba.
La respuesta corta
- ¿Necesita eliminar algunas filas? Utilice
DELETE ... WHERE. - ¿Necesitas vaciar una mesa pero conservarla? Utilice
TRUNCATE, donde sea compatible. - ¿Necesitas que la mesa desaparezca para siempre? Utilice
DROP TABLE.
BORRAR: eliminar filas
DELETE es un comando de cambio de datos (DML). Elimina filas de una en una, activa activadores a nivel de fila y se puede filtrar. Configuramos una pequeña mesa con un disparador de auditoría:
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'
Sólo salió la fila correspondiente y el disparador la registró. Al ejecutar DELETE FROM logs sin una cláusula WHERE, se eliminaron las otras tres filas y la tabla de auditoría contuvo cuatro entradas, una por cada fila eliminada.
DELETE no restablece los contadores de incremento automático. Después de vaciar la tabla, nuestra siguiente inserción recibió id 5, no 1. En SQLite esto se debe a AUTOINCREMENT. Las columnas de identidad de MySQL InnoDB y SQL Server también continúan desde donde estaban después de ELIMINAR.
Consejo: Antes de cualquier DELETE con una cláusula WHERE, ejecute primero la misma cláusula que SELECT COUNT(*). Si el conde te sorprende, detente. Lea nuestra guía sobre valores NULL de SQL para las trampas que NULL crea en una cláusula WHERE.
TRUNCAR: vaciar la tabla
TRUNCATE TABLE logs; elimina todas las filas a la vez. No puede aceptar una cláusula WHERE. En lugar de eliminar filas una por una, la base de datos normalmente libera las páginas de datos de la tabla, razón por la cual es mucho más rápido en tablas grandes.
Cuando lo ejecutamos en SQLite, obtuvimos un error de sintaxis porque SQLite no tiene el comando:
TRUNCATE TABLE logs;
-- near "TRUNCATE": syntax error
En SQLite, use DELETE FROM logs; sin cláusula WHERE. La documentación de SQLite describe una “optimización truncada” que hace que esto sea rápido cuando la tabla no tiene activadores. Nuestra tabla tenía un disparador, por lo que la eliminación se ejecutó fila por fila y se activó para cada fila.
En bases de datos que soportan TRUNCATE, por su documentación:
- Normalmente no activa activadores DELETE a nivel de fila.
- Por lo general, restablece los contadores de identidad o de incremento automático, por ejemplo en MySQL y SQL Server. En PostgreSQL agregas
RESTART IDENTITY. - Necesita permisos más estrictos que ELIMINAR en la mayoría de los sistemas.
DROP: quitar la mesa misma
DROP TABLE es un comando de esquema (DDL). Elimina los datos, la definición de la tabla, sus índices, activadores y restricciones. Todo lo que haga referencia a la tabla, como vistas o claves externas, también se ve afectado.
DROP TABLE logs;
SELECT * FROM logs;
-- no such table: logs
DROP TABLE IF EXISTS logs; -- no error, even though it is gone
IF EXISTS es útil en scripts de configuración que pueden ejecutarse más de una vez. Las vistas en una tabla eliminada pueden romperse, como mostramos en Explicación de las vistas SQL.
tabla comparativa
| Característica | BORRAR | TRUNCAR | CAÍDA |
|---|---|---|---|
| Elimina | Algunas o todas las filas | Todas las filas | Tabla y filas |
| cláusula DONDE | si | No | No |
| Tipo de comando | DML | DDL (normalmente) | DDL |
| Fila provoca incendio | si | Generalmente no | No |
| Restablece la identidad | No | Generalmente si | la mesa se ha ido |
| Velocidad en mesas grandes | Lento | Rápido | Rápido |
| Restos de la mesa | si | si | No |
¿Puedes retroceder?
Aquí es donde muchos artículos simplifican demasiado. La respuesta honesta es que depende de la base de datos.
DELETE se puede revertir dentro de una transacción en todas partes. Lo probamos:
BEGIN;
DELETE FROM logs;
SELECT COUNT(*) FROM logs; -- 0
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 3
DROP también se revirtió en SQLite, que admite DDL transaccional:
BEGIN;
DROP TABLE logs;
ROLLBACK;
SELECT COUNT(*) FROM logs; -- 1 (the table is back)
Para TRUNCATE y DROP en otras bases de datos, según su documentación:
| Base de datos | TRUNCATE/DROP en una transacción |
|---|---|
| PostgreSQL | Se puede revertir. DDL es transaccional. |
| Servidor SQL | Se puede revertir dentro de una transacción explícita. |
| mysql | Provoca una confirmación implícita, por lo que no se puede revertir. |
| Oráculo | Se compromete implícitamente. DROP puede recuperarse de la papelera de reciclaje. |
Por lo tanto, “TRUNCATE nunca se puede revertir” está mal para PostgreSQL y SQL Server, y “siempre se puede revertir” está mal para MySQL. Fuera de una transacción, ninguna de ellas se puede deshacer sin una copia de seguridad.
Por qué TRUNCATE es rápido
DELETE registra cada fila eliminada para que el cambio se pueda deshacer y replicar, activa activadores y verifica las restricciones fila por fila. En una tabla con millones de filas, eso genera mucho trabajo y volumen de registros. TRUNCATE generalmente desasigna el almacenamiento en una sola operación, registrando mucho menos. Para eliminar un subconjunto grande en lugar de todo, elimine en lotes para evitar bloqueos largos. Cubrimos el costo de bloqueo y consulta en optimización de consultas SQL.
Claves externas y permisos
- Claves externas. SQL Server se niega a TRUNCAR una tabla a la que hace referencia una clave externa. PostgreSQL requiere que también truncas las tablas de referencia, o usas
CASCADE. En su lugar, un DELETE verifica cada fila con las restricciones. - Permisos. ELIMINAR necesita derechos de eliminación. TRUNCATE a menudo necesita ALTER o un derecho TRUNCATE dedicado, y DROP necesita propiedad o ALTER en el esquema.
- Replicación y auditoría. Si otros sistemas dependen de activadores o registros de cambios a nivel de fila, TRUNCATE puede omitirlos. Consulte primero con quien sea el propietario de esos sistemas.
cual usar
| Situación | uso |
|---|---|
| Eliminar los pedidos cancelados de un cliente | BORRAR con DONDE |
| Restablecer una tabla de preparación antes de cada ejecución de prueba | TRUNCAR (o ELIMINAR en SQLite) |
| Mantenga en funcionamiento los activadores de auditoría | BORRAR |
| Eliminar una tabla que ya no está en el diseño | DROP en una migración revisada |
| Borre millones de filas antiguas pero mantenga las recientes | ELIMINAR en lotes, o particionar y eliminar particiones antiguas |
Para los datos de prueba, TRUNCATE es popular porque restablece los ID, lo que hace que las pruebas sean repetibles. Envolver cada prueba en una transacción que se revierte es otra opción, que se explica en Transacciones SQL y ACID.
Lista de verificación de seguridad
- Confirme a qué base de datos y entorno está conectado.
- Primero ejecute la cláusula WHERE como SELECT.
- Envuelva el cambio en una transacción donde su base de datos lo admita.
- Tenga una copia de seguridad reciente y probada antes de TRUNCATE o DROP en producción.
- Coloque declaraciones DROP en scripts de migración revisados, nunca en consolas ad-hoc.
- Verifique lo que depende de una tabla, como vistas, claves externas e informes, antes de eliminarla.
Eliminar grandes cantidades de datos de forma segura
Eliminar millones de filas con un DELETE puede bloquear la tabla durante mucho tiempo, llenar el registro de transacciones y ralentizar la replicación. Un patrón común es eliminar en pequeños lotes y repetir hasta que no quede 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);
Ejecute la declaración en un bucle, con una breve pausa entre lotes, hasta que informe cero filas. Cada lote es una transacción pequeña, por lo que los bloqueos son cortos y se siguen ejecutando otras consultas. Un índice en la columna de filtro, aquí created_at, mantiene cada lote rápido.
Para datos que crecen según la fecha, como registros y eventos, particionamiento de tablas es aún mejor. Cada mes vive en su propia partición y eliminar datos antiguos se convierte en una operación rápida que elimina o trunca una partición en lugar de eliminar filas una por una.
Eliminaciones suaves
Muchas aplicaciones nunca eliminan físicamente los registros comerciales. Agregan una columna como deleted_at y la configuran en su lugar, y las consultas luego filtran en deleted_at IS NULL. Las eliminaciones temporales facilitan la recuperación y mantienen el historial para las auditorías, pero cada consulta debe recordar el filtro, lo cual es un buen trabajo para una vista. Las restricciones únicas también necesitan cuidado, porque una fila eliminada temporalmente todavía conserva su valor. Las leyes de privacidad pueden exigir la eliminación real de datos personales después de un período, por lo que las eliminaciones temporales no sustituyen a una política de retención.
Conclusión
DELETE es la herramienta precisa y cuidadosa. TRUNCATE es el botón de reinicio rápido y DROP elimina la tabla por completo. El mayor riesgo es asumir que una base de datos se comporta como otra, especialmente en lo que respecta a la reversión. En caso de duda, pruebe primero el comando en una copia de la tabla en su propia base de datos.
Preguntas frecuentes
¿Cuál es la principal diferencia entre ELIMINAR y TRUNCAR?
DELETE elimina filas una por una, admite WHERE y activa activadores. TRUNCATE elimina todas las filas a la vez, es mucho más rápido, normalmente omite los activadores de filas y, a menudo, restablece los contadores de identidad.
¿Se puede revertir TRUNCATE?
En PostgreSQL y SQL Server, sí, dentro de una transacción. En MySQL y Oracle se confirma implícitamente, por lo que no se puede revertir.
¿ELIMINAR restablece el valor de incremento automático?
No. Después de BORRAR, las nuevas filas continúan desde el contador anterior. En nuestra prueba de SQLite, el siguiente ID fue 5 después de eliminar todas las filas.
¿SQLite admite TRUNCATE?
No. Utilice DELETE FROM tabla sin cláusula WHERE. SQLite optimiza esto cuando la tabla no tiene activadores.
¿Qué elimina DROP TABLE?
Los datos, definición de tablas, índices, desencadenantes y restricciones. Las vistas y claves externas que dependen de la tabla pueden romper o bloquear la caída.
sigue aprendiendo
¿Necesitas ayuda con pruebas, WordPress o SEO?
Ayudamos a los equipos a enviar mejor software y hacer crecer sus sitios. Cuéntenos en qué está trabajando y le sugeriremos un siguiente paso claro.
Más guías sobre testing, IA y desarrollo moderno
¿Te gustó este artículo? Elige un tema y salta directo a nuestros tutoriales más recientes.
Explicación de las alucinaciones de la IA: por qué los modelos de lenguaje inventan cosas y cómo reducirlas
Se explicaron las alucinaciones de la IA: qué son, por qué los modelos de lenguaje las producen, tipos comunes, cómo reducirlas con conexión a tierr…
Leer artículo →DevOpsExplicación de las variables de entorno: archivos .env, secretos y configuración bien hechos
Variables de entorno explicadas con ejemplos de Python que ejecutamos: leerlas y configurarlas, por qué cada valor es una cadena, archivos .env, her…
Leer artículo →Desarrollo de softwareExplicación de la limitación de velocidad de API: algoritmos, encabezados y manejo de errores 429
La limitación de la tasa de API se explica con una simulación que ejecutamos: depósito de tokens, ventana fija, ventana deslizante, 429 respuestas, …
Leer artículo →Automatización de pruebasBurlarse en Python: unittest.mock, patch y los errores que hacen que las pruebas mientan
Burlarse en Python con unittest.mock, probado: Mock y return_value, side_effect, parches donde se usa un nombre, especificación y autospec, fechas d…
Leer artículo →Pruebas de softwareExplicación de la cobertura del código: cobertura de línea versus sucursal y lo que realmente significa 100%
Cobertura del código explicada con una ejecución real de cobertura.py: cobertura de línea, rama y condición, lectura de un informe, por qué una cobe…
Leer artículo →Bases de datos y SQLDELETE vs TRUNCATE vs DROP en SQL: diferencias, reversión y cuándo usar cada uno
DELETE vs TRUNCATE vs DROP explicado con SQL probado: qué elimina cada uno, reversión, activadores, restablecimiento de identidad, velocidad y en qu…
Leer artículo →Bases de datos y SQLVistas SQL explicadas: cree, use y evite los errores, con ejemplos
Vistas SQL explicadas con consultas que ejecutamos: creación de una vista, resultados en vivo, ocultación de columnas, rendimiento, vistas actualiza…
Leer artículo →Desarrollo de softwareInterfaz TypeScript versus tipo: diferencias reales, probadas con el compilador
Interfaz TypeScript versus tipo, verificado con el compilador real: qué pueden hacer ambos, qué puede hacer solo uno, fusión de declaraciones, exten…
Leer artículo →Desarrollo de softwarePython *args y **kwargs explicados: funciones flexibles con ejemplos claros
Python *args y **kwargs explicados con el código que ejecutamos: empaquetado y desempaquetado, orden de parámetros, argumentos solo de palabras clav…
Leer artículo →Desarrollo de softwareFunciones Lambda de Python: sintaxis, usos reales y cuándo no utilizarlas
Funciones lambda de Python explicadas con el código que ejecutamos: sintaxis, clasificación con clave, mapa y filtro, cierres, trampa de enlace tard…
Leer artículo →Inteligencia artificial¿Qué son los agentes de IA? Cómo funcionan, con un bucle de agente simple que puedes ejecutar
¿Qué son los agentes de IA? Una guía sencilla sobre el bucle del agente, las herramientas, la memoria y las barreras de seguridad, con un pequeño bu…
Leer artículo →DevOpsMonitoreo versus observabilidad: la verdadera diferencia, con registros, métricas y seguimientos
Explicación del monitoreo versus observabilidad: fallas conocidas y desconocidas, registros, métricas y seguimientos, un recorrido por incidentes de…
Leer artículo →DevOpsDocker Volumes versus Bind Mounts: persistir los datos del contenedor de la manera correcta
Se explican los volúmenes de Docker frente a los montajes de enlace: por qué desaparecen los datos del contenedor, volúmenes con nombre, montajes de…
Leer artículo →Automatización de pruebasTDD vs BDD: diferencias clave, una función creada en ambos sentidos y cuándo usar cada una
TDD vs BDD explicado con una característica de descuento construida en ambos sentidos: refactor rojo-verde con el código que ejecutamos, escenarios …
Leer artículo →Desarrollo de softwareGit merge vs rebase: diferencias, ejemplos y cuándo usar cada uno
Git merge vs rebase explicado con salida real del log, una tabla comparativa, la regla de oro del rebase y un flujo de trabajo seguro para equipos.
Leer artículo →Desarrollo de softwareList comprehension en Python: sintaxis, ejemplos y cuándo evitarla
List comprehension en Python explicada: sintaxis, filtros, if-else, bucles anidados, tiempos medidos y cuándo es mejor un bucle for normal.
Leer artículo →