TRUNCATE TABLE
TRUNCATE TABLE
Definition
TRUNCATE TABLE quickly removes all rows from a table while keeping its structure (columns, constraints, indexes) intact. It is optimized for speed: rather than deleting rows one at a time, it deallocates the data pages wholesale.
sqlTRUNCATE TABLE staging_orders; -- Postgres extras: TRUNCATE TABLE staging_orders RESTART IDENTITY CASCADE;
TRUNCATE vs DELETE (Recap and Contrast)
| Aspect | TRUNCATE TABLE | DELETE |
|---|---|---|
| Row selection | Whole table only, no WHERE | Can filter with WHERE |
| Speed on large tables | Very fast (deallocates pages) | Slower (row-by-row, fully logged) |
| Logging | Minimal | Full row-level logging |
| Triggers | Row-level triggers typically do not fire | Row-level triggers fire normally |
| Identity/auto-increment | Resets the counter (engine-dependent, see below) | Does not reset the counter |
| Transactional rollback | Dialect-dependent — see below | Always rollback-able within a transaction |
The Dialect Nuance on Transactionality (Important)
A common but overly broad claim is "TRUNCATE cannot be rolled back." This is engine-dependent:
- PostgreSQL and SQL Server:
TRUNCATEgenuinely can be run inside a transaction and rolled back before commit — it is fully transactional there. - MySQL/InnoDB:
TRUNCATE TABLEcauses an implicit commit (like other DDL), so it effectively cannot be rolled back once executed, behaving much more likeDROP TABLE+CREATE TABLEunder the hood.
Always verify this behavior on your specific engine before relying on it in a script that assumes rollback safety.
Worked Example
A nightly ETL job needs to clear a staging table before reloading fresh data, and wants the identity counter reset for cleanliness:
sqlBEGIN; TRUNCATE TABLE staging_orders RESTART IDENTITY; COPY staging_orders FROM '/data/today_orders.csv' WITH (FORMAT csv); COMMIT; -- on Postgres, this whole block is atomic; a failure before COMMIT rolls everything back
Using DELETE FROM staging_orders; instead would work too, but would be dramatically slower on a multi-million-row staging table and would generate far more transaction log/WAL volume.
Edge Cases and Pitfalls
- Fails in the presence of foreign keys referencing the table (in Postgres/SQL Server) unless
CASCADEis used or the referencing rows are handled — you can't truncate a table that other rows still point to. - Resets auto-increment/identity counters by default in many engines (e.g., MySQL always resets; Postgres requires the explicit
RESTART IDENTITYoption, otherwise the counter is left untouched by defaultCONTINUE IDENTITY). - Does not fire row-level `AFTER DELETE` triggers in most engines — code relying on delete triggers for auditing will silently miss truncations.
- Despite being "DDL-like" in behavior, syntactically it still reads like a DML statement (
TRUNCATE TABLE x;), which confuses newcomers about why it resets identity counters whileDELETE FROM x;does not.
Key Takeaways / Q&A
Q: Can I TRUNCATE just some rows matching a condition? A: No — TRUNCATE always affects 100% of the table's rows; for a filtered removal use DELETE ... WHERE ....
Q: Does TRUNCATE reset auto-increment counters? A: Typically yes (this is one of its defining differences from DELETE), though the exact default/option varies by engine (Postgres needs RESTART IDENTITY explicitly).