system onlinepath: /guias/bases-de-datos/delete-truncate-y-drop-diferencias/mode: knowledge_baselocal:
Datos y bases de datos · Nivel inicial

DELETE, TRUNCATE y DROP: diferencias y cuándo utilizarlos

Las tres sentencias borran datos, pero no son intercambiables: pertenecen a categorías distintas del lenguaje SQL y se comportan de forma muy diferente según el motor. Esta guía compara DELETE, TRUNCATE y DROP TABLE en PostgreSQL, MySQL y SQLite: qué se puede revertir, qué pasa con los contadores y las claves foráneas, y cuándo conviene cada una.

14 min de lectura▣ Actualizada el ◇ Por Underc0de
Respuesta rápida

DELETE, TRUNCATE y DROP TABLE borran datos, pero no son intercambiables. DELETE es DML (Data Manipulation Language, lenguaje de manipulación de datos): borra filas que cumplen una condición, de a una, y puede revertirse con ROLLBACK. TRUNCATE y DROP TABLE son DDL (Data Definition Language, lenguaje de definición de datos): TRUNCATE vacía la tabla entera sin condición, y DROP TABLE la elimina junto con su estructura. La sorpresa está en el motor: en PostgreSQL las dos son transaccionales y se revierten sin drama; en MySQL con InnoDB provocan un COMMIT implícito y no hay vuelta atrás; SQLite ni siquiera tiene TRUNCATE. Elegir mal cuál usar puede costarte datos que creías poder recuperar.

Ver índice de contenidos
  1. 01Qué borra cada uno y de qué tipo es
  2. 02El punto que más sorprende: la transaccionalidad
  3. 03Qué pasa con los contadores
  4. 04Claves foráneas: cuándo fallan
  5. 05Triggers: qué se dispara y qué no
  6. 06Por qué DELETE es más lento
  7. 07Cuál usar en cada caso
  8. 08Errores frecuentes
  9. 09Preguntas frecuentes
  10. 10Fuentes

Qué borra cada uno y de qué tipo es

Las tres sentencias borran algo, pero apuntan a blancos distintos. DELETE borra filas: podés decirle exactamente cuáles con una cláusula WHERE, o dejarlo sin condición y borrar todas, una por una. TRUNCATE TABLE vacía la tabla entera de una sola vez: no acepta condición, y la tabla sigue existiendo, vacía. DROP TABLE va más allá: elimina la tabla completa, con sus filas, estructura, índices y triggers. Después de un DROP TABLE no hay «tabla vacía» a la que volver. Si todavía no tenés claro cómo se arma una consulta SQL básica, conviene repasar antes introducción a SQL desde cero.

DML y DDL

Esta diferencia corresponde a una clasificación del propio lenguaje SQL. DELETE pertenece al DML (Data Manipulation Language): trabaja sobre las filas. TRUNCATE y DROP TABLE pertenecen al DDL (Data Definition Language): trabajan sobre la estructura, aunque TRUNCATE de paso vacíe el contenido. La documentación de MySQL lo aclara para TRUNCATE TABLE, y la distinción es la misma en PostgreSQL y en SQLite, con la salvedad de que SQLite no tiene TRUNCATE.

Qué borra cada sentencia y su clasificación
SentenciaQué borraClasificación
DELETEFilas que cumplen una condición (o todas, sin WHERE)DML
TRUNCATE TABLETodas las filas; la tabla sigue existiendo, vacíaDDL
DROP TABLELa tabla completa: filas, estructura, índices y triggersDDL

El punto que más sorprende: la transaccionalidad

Acá es donde DELETE, TRUNCATE y DROP dejan de comportarse igual entre motores. Si ya sabés qué es una transacción y qué hacen COMMIT y ROLLBACK, saltá directo a la tabla; si no, conviene repasar antes transacciones y ACID en bases de datos.

Diagrama con tres tarjetas superiores para DELETE (DML), TRUNCATE (DDL) y DROP TABLE (DDL), y una franja inferior que contrasta el comportamiento transaccional de PostgreSQL, MySQL con InnoDB y SQLite ante TRUNCATE y DROP TABLE. PostgreSQL: son transaccionales y se revierten con ROLLBACK. MySQL con InnoDB: provocan un commit implícito, no se pueden revertir y cierran cualquier transacción abierta. SQLite: no existe TRUNCATE, se usa DELETE FROM sin WHERE, optimizado internamente pero igualmente transaccional.
DELETE es DML; TRUNCATE y DROP son DDL. Esa clasificación es igual en los tres motores: lo que cambia de verdad entre ellos es la transaccionalidad.
Comportamiento transaccional de TRUNCATE y DROP TABLE por motor
AspectoPostgreSQLMySQL (InnoDB)SQLite
¿Existe TRUNCATE?No: se usa DELETE FROM tabla sin WHERE
TRUNCATE / DROP TABLE, ¿son transaccionales?Sí: se revierten con ROLLBACKNo: provocan un COMMIT implícito, no se pueden revertirNo aplica TRUNCATE; el DELETE sí es transaccional
¿Qué pasa con una transacción ya abierta?Sigue abierta, sin efectos extraSe cierra sola por el commit implícitoSigue abierta, sin efectos extra
Contador o secuencia al vaciarNo cambia, salvo RESTART IDENTITYEl AUTO_INCREMENT se reseteaNo aplica (no hay TRUNCATE)
SQL
-- PostgreSQL: TRUNCATE es transaccional
BEGIN;
TRUNCATE TABLE pedidos;
ROLLBACK;
-- pedidos conserva sus filas: el TRUNCATE se revirtió sin dejar rastro
SQL
-- MySQL con InnoDB: TRUNCATE hace un commit implícito
START TRANSACTION;
DELETE FROM clientes WHERE id = 8;
TRUNCATE TABLE pedidos;  -- acá ya se confirmó todo, sin que pidieras COMMIT
ROLLBACK;                -- no revierte nada: no queda ninguna transacción abierta
SQL
-- SQLite no tiene TRUNCATE: se usa DELETE FROM sin WHERE
BEGIN;
DELETE FROM pedidos;
ROLLBACK;
-- esto sí revierte el borrado completo: sigue siendo DML transaccional

El caso de MySQL es el que más sorprende: además de no poder deshacer el TRUNCATE o el DROP TABLE, cualquier transacción abierta con otros cambios sin confirmar se cierra en ese mismo momento. Si estabas en medio de una operación con varios pasos y metés un TRUNCATE pensando en arrepentirte después, en MySQL con InnoDB ya es tarde: se guardó todo, lo que tenías antes incluido.

i
Antes de un TRUNCATE o un DROP TABLE en MySQL

Como no hay ROLLBACK posible, la única red de seguridad real es una copia de seguridad previa. Si no tenés una rutina de respaldo probada, revisá copias de seguridad y restauración de bases de datos antes de ejecutar cualquiera de las dos en producción.

Qué pasa con los contadores

Vaciar una tabla no siempre reinicia la numeración de sus filas. En MySQL, TRUNCATE TABLE resetea el contador AUTO_INCREMENT: la próxima fila insertada vuelve a empezar desde el valor inicial, normalmente 1. En PostgreSQL el comportamiento por defecto es el opuesto: TRUNCATE no toca las secuencias asociadas —CONTINUE IDENTITY, la opción implícita—, así que la próxima fila sigue la numeración donde había quedado. Para el mismo efecto que en MySQL hay que pedirlo con RESTART IDENTITY.

SQL
TRUNCATE TABLE pedidos;                    -- PostgreSQL: CONTINUE IDENTITY implícito, la secuencia no se toca
TRUNCATE TABLE pedidos RESTART IDENTITY;   -- reinicia la secuencia asociada

DELETE, en cambio, no resetea contadores en ningún motor: borrar todas las filas con un DELETE FROM tabla sin WHERE deja la secuencia o el AUTO_INCREMENT donde estaba. Es fácil de comprobar: si insertás después de un DELETE masivo, el identificador sigue la numeración anterior; si insertás después de un TRUNCATE en MySQL, arranca de nuevo.

Claves foráneas: cuándo fallan

Una clave foránea (FK, de Foreign Key) es una restricción que obliga a que un valor de una tabla exista también en otra. TRUNCATE, al vaciar la tabla de golpe, choca con esa restricción cuando otra tabla la referencia. En MySQL con InnoDB, TRUNCATE TABLE falla directamente si existen claves foráneas de otras tablas apuntando a la que querés vaciar. En PostgreSQL el comportamiento por defecto es el mismo —también falla—, salvo que incluyas en el mismo TRUNCATE las tablas dependientes, o agregues CASCADE.

Acá conviene un matiz que se presta a confusión, porque CASCADE significa cosas distintas según el contexto. En un TRUNCATE con CASCADE en PostgreSQL, lo que se vacía en cascada son las tablas dependientes: si truncás pedidos y detalles_pedido tiene una FK hacia pedidos, CASCADE también vacía detalles_pedido. Es distinto de un DROP TABLE con CASCADE, donde CASCADE no borra la tabla referenciada: elimina la restricción de clave foránea que dependía de la tabla borrada, y la otra tabla queda intacta. Confundir los dos usos es un error potencialmente grave: uno vacía datos de otra tabla, el otro solo quita una regla de integridad.

SQL
-- PostgreSQL: los dos CASCADE no hacen lo mismo
TRUNCATE TABLE pedidos CASCADE;   -- también vacía las tablas que dependen de pedidos
DROP TABLE pedidos CASCADE;       -- borra pedidos y elimina las FK que dependían de ella (no borra esas tablas)

Con DROP TABLE el comportamiento es parecido en ambos motores: si otra tabla tiene una clave foránea apuntando a la que querés eliminar, el DROP falla salvo que uses CASCADE (con el significado que acabás de ver) o borres antes la restricción o la tabla dependiente.

Triggers: qué se dispara y qué no

Un trigger es un bloque de código que la base de datos ejecuta automáticamente ante un evento sobre una tabla, como un INSERT, un UPDATE o un DELETE. DELETE, al procesar fila por fila, dispara los triggers ON DELETE definidos sobre la tabla: si tenés uno que registra bajas o descuenta stock, se ejecuta por cada fila borrada. TRUNCATE no pasa por ese camino: en MySQL, TRUNCATE TABLE no dispara los triggers ON DELETE, así que cualquier lógica que dependa de ellos simplemente no se ejecuta. Es una fuente de errores difíciles de detectar, porque a simple vista TRUNCATE «parece» un DELETE de todas las filas, pero no activa lo mismo.

DROP TABLE elimina la tabla entera, y con ella sus triggers: no queda nada que disparar, porque no queda tabla. En SQLite, además, el proceso interno de DROP TABLE borra primero los triggers y recién después aplica un DELETE implícito para mantener las claves foráneas, así que tampoco se disparan.

Por qué DELETE es más lento

A igualdad de filas borradas, DELETE tarda más que TRUNCATE o DROP TABLE. DELETE procesa y registra el borrado fila por fila: por cada una verifica la condición del WHERE, dispara los triggers correspondientes y guarda lo necesario para poder revertir con ROLLBACK. Ese registro fila por fila es lo que le permite ser reversible y disparar triggers, pero tiene un costo.

TRUNCATE y DROP TABLE no necesitan nada de eso: operan a nivel de página de datos o sobre los metadatos de la tabla, sin recorrer ni registrar cada fila. La documentación de MySQL lo dice de forma explícita: cuando no importa cuántas filas se borraron ni hace falta disparar triggers ON DELETE, TRUNCATE TABLE es más rápido que un DELETE sin WHERE.

Esto no convierte a TRUNCATE en «un DELETE rápido» sin más: es una operación distinta, con las otras consecuencias que ya viste. La velocidad es real, pero no alcanza como único criterio para elegir.

Cuál usar en cada caso

  1. ¿Necesitás borrar algunas filas según una condición?Usá DELETE. Es la única de las tres que acepta WHERE, y la que dispara triggers ON DELETE.
  2. ¿Necesitás vaciar una tabla completa y te importa la velocidad?Usá TRUNCATE, sabiendo que en MySQL no hay vuelta atrás y que puede resetear el contador.
  3. ¿La tabla ya no tiene ningún uso futuro?Usá DROP TABLE, con una copia de seguridad hecha antes si hay la mínima duda.
  4. ¿Estás en MySQL, dentro de una transacción con varios pasos, sin confirmar todavía?Evitá TRUNCATE y DROP TABLE hasta el final: cierran la transacción antes de tiempo.

Las precauciones generales antes de borrar —probar primero con un SELECT, trabajar sobre una copia— ya están cubiertas en cómo eliminar registros duplicados con SQL. Esta guía no repite esas prácticas: se enfoca en la diferencia entre las tres sentencias.

Errores frecuentes

  • Creer que TRUNCATE es «un DELETE rápido» sin más. Cambia la transaccionalidad, los contadores, los triggers y el comportamiento con claves foráneas.
  • Confiar en el ROLLBACK después de un TRUNCATE sin conocer el motor. Funciona en PostgreSQL; en MySQL con InnoDB ya es tarde, el commit fue implícito.
  • Confundir «borrar todas las filas» con «borrar la tabla». Son operaciones distintas con consecuencias distintas: una deja la tabla vacía, la otra la hace desaparecer.
  • Suponer que TRUNCATE siempre resetea los contadores. En PostgreSQL solo pasa si pedís RESTART IDENTITY.
  • Pensar que TRUNCATE dispara los mismos triggers que DELETE. En MySQL, no dispara ON DELETE.
  • Ejecutar DROP TABLE o TRUNCATE en MySQL sin backup previo. Es la única red de seguridad real cuando no hay ROLLBACK posible.

Preguntas frecuentes

¿TRUNCATE se puede revertir con ROLLBACK?

Depende del motor. En PostgreSQL, sí: TRUNCATE es transaccional, así que un ROLLBACK dentro de la misma transacción la deshace sin dejar rastro, igual que revertiría un UPDATE o un DELETE. En MySQL con InnoDB, no: TRUNCATE TABLE provoca un commit implícito, confirmando de forma automática cualquier transacción abierta en ese momento, incluida la que envolvía al TRUNCATE. Una vez que eso ocurre, no hay ROLLBACK que valga: lo truncado quedó confirmado, junto con cualquier otro cambio pendiente de esa misma transacción. En SQLite la pregunta no aplica igual porque no existe TRUNCATE: el vaciado se hace con un DELETE FROM sin condición, que sigue siendo DML y, como tal, reversible con ROLLBACK mientras no se confirme. Nunca asumas que un TRUNCATE es reversible sin confirmar antes qué motor estás usando.

¿Por qué DELETE es más lento si borran lo mismo?

Porque trabajan de maneras distintas por dentro, aunque el resultado visible parezca el mismo. DELETE recorre la tabla fila por fila: evalúa la condición del WHERE, dispara los triggers ON DELETE y registra la operación para poder deshacerla con ROLLBACK. Ese trabajo por fila tiene un costo que crece con la cantidad de filas. TRUNCATE y DROP TABLE operan a un nivel más alto: liberan páginas de almacenamiento completas o eliminan directamente los metadatos, sin la contabilidad que exige poder revertir cada fila ni disparar triggers. La documentación de MySQL lo dice de forma explícita: cuando no importa cuántas filas se borraron ni hace falta disparar triggers, TRUNCATE TABLE es más rápido que un DELETE sin WHERE. La diferencia se nota en tablas grandes. Esa velocidad no alcanza como único criterio: hay que sumarle la transaccionalidad, los contadores, las claves foráneas y los triggers.

¿Qué pasa con el AUTO_INCREMENT o la secuencia al truncar?

Depende del motor y de lo que le pidas explícitamente. En MySQL, TRUNCATE TABLE resetea el AUTO_INCREMENT: después de truncar, la próxima fila insertada vuelve a empezar desde el valor inicial, típicamente 1. En PostgreSQL el comportamiento por defecto es el contrario: TRUNCATE no reinicia las secuencias asociadas —CONTINUE IDENTITY, la opción implícita—, así que la próxima fila sigue la numeración donde había quedado. Para el mismo efecto que en MySQL hay que pedirlo con RESTART IDENTITY. En SQLite la pregunta no aplica igual porque no existe TRUNCATE: el vaciado se hace con DELETE FROM, y ese DELETE tampoco resetea contadores en ningún motor. Conviene comprobar el comportamiento por defecto del motor antes de asumir que vaciar una tabla también reinicia su numeración.

¿Puedo truncar una tabla si otra la referencia con una clave foránea?

En general no, salvo que lo indiques de forma explícita. Una clave foránea (FK, de Foreign Key) obliga a que un valor de una tabla exista también en otra, y vaciar de golpe la tabla referenciada dejaría huérfanas esas referencias. En MySQL con InnoDB, TRUNCATE TABLE falla si hay claves foráneas de otras tablas apuntando a la que querés vaciar. En PostgreSQL el comportamiento por defecto es equivalente: también falla, salvo que incluyas en el mismo TRUNCATE las tablas dependientes, o agregues CASCADE. Ojo con un matiz: en un TRUNCATE, CASCADE vacía también las tablas dependientes; en un DROP TABLE, en cambio, CASCADE elimina la restricción de clave foránea que dependía de la tabla eliminada, sin borrar ni vaciar la otra tabla. Confundir estos dos usos puede llevar a borrar datos que no querías tocar.

¿SQLite tiene TRUNCATE?

No, SQLite no incluye TRUNCATE en su lenguaje, a diferencia de PostgreSQL y de MySQL. Para vaciar por completo una tabla se usa DELETE FROM tabla sin ninguna cláusula WHERE. La documentación de SQLite aclara que este DELETE sin condición está optimizado internamente para no evaluar la condición fila por fila, acercándose en velocidad a un TRUNCATE. Pero sigue siendo una sentencia DML (Data Manipulation Language) transaccional: si se ejecuta dentro de una transacción sin confirmar, un ROLLBACK la revierte sin problema, algo que no se puede dar por sentado con un TRUNCATE en MySQL. Tampoco resetea ningún contador por vaciar la tabla. Si migrás scripts SQL entre motores y te encontrás con un TRUNCATE TABLE pensado para PostgreSQL o MySQL, hay que reescribirlo como DELETE FROM tabla para SQLite.

¿DROP TABLE dispara los triggers antes de borrar la tabla?

No dispara los triggers como si fuera un borrado de filas: los elimina junto con la tabla, sin ejecutarlos. Un trigger es un bloque de código que la base de datos ejecuta automáticamente ante un evento sobre una tabla, como un INSERT, un UPDATE o un DELETE, y pertenece a la tabla donde está definido. Al ejecutar un DROP TABLE se elimina la tabla completa —filas, estructura, índices y triggers—, así que no queda ningún objeto sobre el que puedan dispararse. Es distinto de TRUNCATE en MySQL, donde la tabla sigue existiendo vacía pero sus triggers ON DELETE no se activan; con DROP TABLE directamente no quedan triggers porque no queda tabla. En SQLite, el propio proceso interno de DROP TABLE borra primero los triggers y recién después aplica un DELETE implícito por claves foráneas.

Fuentes

Documentación oficial y material de la comunidad consultados para esta guía. Fecha de consulta: 29 de julio de 2026.

Aportes de la comunidad Underc0de

  1. Underc0de, foro. Resumen de SQL y su Sintaxis, por Mr. Bones, sección Base de Datos, 9 de agosto de 2023. Incluye la sintaxis de las tres sentencias, pero no compara su comportamiento entre motores: mención tangencial, no fuente de los hechos técnicos de esta guía. No hay en el foro ningún hilo que compare específicamente DELETE, TRUNCATE y DROP.

Documentación oficial

  1. PostgreSQL. DELETE. Sintaxis y comportamiento transaccional de la sentencia.
  2. PostgreSQL. TRUNCATE. Transaccionalidad, RESTART IDENTITY/CONTINUE IDENTITY y CASCADE.
  3. PostgreSQL. DROP TABLE. Comportamiento con dependencias y CASCADE.
  4. MySQL. DELETE Statement. Comportamiento fila por fila y triggers.
  5. MySQL. TRUNCATE TABLE Statement. Clasificación como DDL, commit implícito, AUTO_INCREMENT, claves foráneas y triggers.
  6. MySQL. DROP TABLE Statement. Eliminación de la tabla y sus dependientes.
  7. SQLite. DELETE. Optimización interna del DELETE sin WHERE, sin TRUNCATE en el lenguaje.
  8. SQLite. DROP TABLE. Eliminación de triggers asociados al eliminar la tabla.