1. Home
  2. Blog
  3. Databases & SQL

Databases & SQL

DELETE vs TRUNCATE vs DROP: Differences, Rollback and When to Use Each

All three commands remove something, but they remove different things in different ways. Here is what each one does, what you can undo, and how the rules change between databases.

8 min read
DELETE vs TRUNCATE vs DROP in SQL: differences, rollback and when to use each

Key takeaways

  • DELETE removes rows, optionally filtered with WHERE. The table stays.
  • TRUNCATE removes all rows quickly. The table structure stays.
  • DROP removes the whole table: data, structure, indexes and triggers.
  • Rollback, triggers and identity reset behave differently in each database, so check yours.

A tester wants to clear a staging table before a fresh test run. Should it be DELETE, TRUNCATE or DROP? The wrong choice can mean a slow job, a missing table, or, in production, a very bad afternoon.

We ran the DELETE and DROP examples below in SQLite 3.50, and the outputs come from that run. SQLite has no TRUNCATE command, so the TRUNCATE notes are based on the official PostgreSQL, MySQL and SQL Server documentation rather than our own test.

The short answer

  • Need to remove some rows? Use DELETE ... WHERE.
  • Need to empty a table but keep it? Use TRUNCATE, where it is supported.
  • Need the table gone for good? Use DROP TABLE.

DELETE: remove rows

DELETE is a data change (DML) command. It removes rows one at a time, fires row-level triggers and can be filtered. We set up a small table with an audit trigger:

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'

Only the matching row went, and the trigger recorded it. Running DELETE FROM logs without a WHERE clause removed the other three rows, and the audit table then held four entries, one per deleted row.

DELETE does not reset auto-increment counters. After emptying the table, our next insert received id 5, not 1. In SQLite this is because of AUTOINCREMENT. MySQL InnoDB and SQL Server identity columns also continue from where they were after a DELETE.

Tip: Before any DELETE with a WHERE clause, run the same clause as a SELECT COUNT(*) first. If the count surprises you, stop. Read our guide to SQL NULL values for the traps NULL creates in a WHERE clause.

TRUNCATE: empty the table

TRUNCATE TABLE logs; removes every row at once. It cannot take a WHERE clause. Instead of deleting rows one by one, the database typically releases the table’s data pages, which is why it is much faster on large tables.

When we ran it in SQLite, we got a syntax error, because SQLite does not have the command:

TRUNCATE TABLE logs;
-- near "TRUNCATE": syntax error

In SQLite, use DELETE FROM logs; with no WHERE clause. SQLite’s documentation describes a “truncate optimization” that makes this fast when the table has no triggers. Our table had a trigger, so the delete ran row by row and fired it for each row.

In databases that support TRUNCATE, by their documentation:

  • It normally does not fire row-level DELETE triggers.
  • It usually resets identity or auto-increment counters, for example in MySQL and SQL Server. In PostgreSQL you add RESTART IDENTITY.
  • It needs stronger permissions than DELETE in most systems.

DROP: remove the table itself

DROP TABLE is a schema (DDL) command. It removes the data, the table definition, its indexes, triggers and constraints. Anything that refers to the table, such as views or foreign keys, is affected too.

DROP TABLE logs;
SELECT * FROM logs;
-- no such table: logs

DROP TABLE IF EXISTS logs;  -- no error, even though it is gone

IF EXISTS is handy in setup scripts that may run more than once. Views on a dropped table can break, as we showed in SQL views explained.

Comparison table

Feature DELETE TRUNCATE DROP
Removes Some or all rows All rows Table and rows
WHERE clause Yes No No
Command type DML DDL (usually) DDL
Row triggers fire Yes Usually no No
Resets identity No Usually yes Table is gone
Speed on big tables Slow Fast Fast
Table remains Yes Yes No

Can you roll back?

This is where a lot of articles oversimplify. The honest answer is that it depends on the database.

DELETE can be rolled back inside a transaction everywhere. We tested it:

BEGIN;
DELETE FROM logs;
SELECT COUNT(*) FROM logs;  -- 0
ROLLBACK;
SELECT COUNT(*) FROM logs;  -- 3

DROP also rolled back in SQLite, which supports transactional DDL:

BEGIN;
DROP TABLE logs;
ROLLBACK;
SELECT COUNT(*) FROM logs;  -- 1 (the table is back)

For TRUNCATE and DROP in other databases, according to their documentation:

Database TRUNCATE / DROP in a transaction
PostgreSQL Can be rolled back. DDL is transactional.
SQL Server Can be rolled back inside an explicit transaction.
MySQL Causes an implicit commit, so it cannot be rolled back.
Oracle Commits implicitly. DROP may be recoverable from the recycle bin.

So “TRUNCATE can never be rolled back” is wrong for PostgreSQL and SQL Server, and “it can always be rolled back” is wrong for MySQL. Outside a transaction, none of them can be undone without a backup.

Why TRUNCATE is fast

DELETE logs each removed row so the change can be undone and replicated, fires triggers and checks constraints row by row. On a table with millions of rows, that creates a lot of work and log volume. TRUNCATE generally deallocates the storage in one operation, logging far less. To remove a large subset rather than everything, delete in batches so you avoid long locks. We cover locking and query cost in SQL query optimization.

Foreign keys and permissions

  • Foreign keys. SQL Server refuses to TRUNCATE a table referenced by a foreign key. PostgreSQL requires you to truncate the referencing tables too, or use CASCADE. A DELETE checks each row against the constraints instead.
  • Permissions. DELETE needs delete rights. TRUNCATE often needs ALTER or a dedicated TRUNCATE right, and DROP needs ownership or ALTER on the schema.
  • Replication and audit. If other systems depend on row-level change logs or triggers, TRUNCATE may skip them. Check with whoever owns those systems first.

Which one to use

Situation Use
Remove a customer’s cancelled orders DELETE with WHERE
Reset a staging table before each test run TRUNCATE (or DELETE in SQLite)
Keep audit triggers working DELETE
Remove a table no longer in the design DROP in a reviewed migration
Clear millions of old rows but keep recent ones DELETE in batches, or partition and drop old partitions

For test data, TRUNCATE is popular because it resets IDs, which makes tests repeatable. Wrapping each test in a transaction that is rolled back is another option, explained in SQL transactions and ACID.

Safety checklist

  1. Confirm which database and environment you are connected to.
  2. Run the WHERE clause as a SELECT first.
  3. Wrap the change in a transaction where your database supports it.
  4. Have a recent, tested backup before TRUNCATE or DROP in production.
  5. Put DROP statements in reviewed migration scripts, never in ad-hoc consoles.
  6. Check what depends on a table, such as views, foreign keys and reports, before dropping it.

Deleting large amounts of data safely

Removing millions of rows with one DELETE can lock the table for a long time, fill the transaction log and slow replication. A common pattern is to delete in small batches and repeat until nothing is left:

-- 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);

Run the statement in a loop, with a short pause between batches, until it reports zero rows. Each batch is a small transaction, so locks are short and other queries keep running. An index on the filter column, here created_at, keeps every batch fast.

For data that grows by date, such as logs and events, table partitioning is even better. Each month lives in its own partition, and removing old data becomes a quick operation that drops or truncates one partition instead of deleting rows one by one.

Soft deletes

Many applications never physically delete business records. They add a column such as deleted_at and set it instead, and queries then filter on deleted_at IS NULL. Soft deletes make recovery easy and keep history for audits, but every query must remember the filter, which is a good job for a view. Unique constraints also need care, because a soft-deleted row still holds its value. Privacy laws may require real deletion of personal data after a period, so soft deletes are not a substitute for a retention policy.

Final thoughts

DELETE is the precise, careful tool. TRUNCATE is the fast reset button, and DROP removes the table entirely. The biggest risk is assuming one database behaves like another, especially around rollback. When in doubt, test the command on a copy of the table in your own database first.

Frequently asked questions

What is the main difference between DELETE and TRUNCATE?

DELETE removes rows one by one, supports WHERE and fires triggers. TRUNCATE removes all rows at once, is much faster, usually skips row triggers and often resets identity counters.

Can TRUNCATE be rolled back?

In PostgreSQL and SQL Server, yes, inside a transaction. In MySQL and Oracle it commits implicitly, so it cannot be rolled back.

Does DELETE reset the auto-increment value?

No. After a DELETE, new rows continue from the previous counter. In our SQLite test, the next ID was 5 after deleting all rows.

Does SQLite support TRUNCATE?

No. Use DELETE FROM table with no WHERE clause. SQLite optimizes this when the table has no triggers.

What does DROP TABLE remove?

The data, table definition, indexes, triggers and constraints. Views and foreign keys that depend on the table can break or block the drop.

Keep learning

Work with Stack Quora

Need help with testing, WordPress or SEO?

We help teams ship better software and grow their sites. Tell us what you are working on and we will suggest a clear next step.

Keep reading

More guides on testing, AI & modern development

Enjoyed this article? Pick a topic and jump straight into our newest tutorials.

Artificial Intelligence

LLM Structured Output Explained: Getting Reliable JSON From AI Models

LLM structured output explained with validation we ran in Pydantic: JSON mode and schemas, constrained decoding, the ways model output…

Read article →
DevOps

SSH Keys Explained: How They Work, ssh-keygen, Ed25519 and Safe Habits

SSH keys explained with keys we generated: public vs private keys, ssh-keygen, Ed25519 vs RSA, fingerprints, passphrases, ssh-agent, authorized_keys, config…

Read article →
DevOps

HTTP Caching Explained: Cache-Control, ETag and 304 Responses, With a Live Test

HTTP caching explained with a small server we ran: Cache-Control directives, max-age, no-cache vs no-store, ETag revalidation and 304 responses,…

Read article →
Test Automation

API Contract Testing Explained: Catch Breaking Changes Before They Ship

API contract testing explained with a schema check we ran: what a contract is, consumer-driven contracts, Pact, OpenAPI, which changes…

Read article →
Software Testing

Risk-Based Testing Explained: Score Risks, Build a Matrix and Test What Matters

Risk-based testing explained step by step: identifying risks, scoring likelihood and impact, building a risk matrix, mapping risk to test…

Read article →
Databases & SQL

SQL Constraints Explained: NOT NULL, UNIQUE, CHECK and FOREIGN KEY, Tested

SQL constraints explained with tests we ran: NOT NULL, UNIQUE, CHECK, DEFAULT, PRIMARY and FOREIGN KEY, the NULL loopholes, SQLite's…

Read article →
Databases & SQL

SQL Date Functions Explained: Adding, Comparing and Grouping Dates Without Bugs

SQL date functions explained with queries we ran: adding intervals, month-end surprises, date differences, the BETWEEN trap, grouping by day,…

Read article →
Software Development

Python asyncio Explained: async, await, gather and TaskGroup With Real Timings

Python asyncio explained with code we timed: coroutines, await, gather, TaskGroup, error handling, timeouts, limiting concurrency and the blocking-call mistake…

Read article →
Software Development

Debounce vs Throttle in JavaScript: How They Work, When to Use Each, Tested

Debounce vs throttle in JavaScript explained with timings we measured in Node.js: how each works, simple implementations, leading and trailing…

Read article →
Software Development

Python Context Managers Explained: The with Statement, contextlib and Real Uses

Python context managers explained with code we ran: how with works, __enter__ and __exit__, contextlib.contextmanager, suppress, ExitStack, database transactions and…

Read article →
Artificial Intelligence

LLM Temperature and Top-p Explained: How AI Models Choose Their Next Word

LLM temperature and top-p explained with a simulation we ran: how probabilities are reshaped, what top-p keeps, recommended settings by…

Read article →
DevOps

YAML Explained: Syntax, the Norway Problem and Other Traps We Tested

YAML explained with a parser test: basic syntax, lists and maps, the Norway problem, versions turning into floats, octal zip…

Read article →
DevOps

Cron Jobs Explained: Syntax, Real Schedules and the Mistakes That Break Them

Cron jobs explained with schedules we verified: the five fields, operators, real examples, the day-of-month OR day-of-week trap, environment problems,…

Read article →
Software Testing

Bug Life Cycle in Software Testing: Every Status, Who Owns It and Common Mistakes

The bug life cycle explained: every defect status from New to Closed, who owns each step, rejected, deferred and reopened…

Read article →
Test Automation

Property-Based Testing in Python: Hypothesis Finds the Bugs Your Examples Miss

Property-based testing explained with Hypothesis tests we ran: properties vs examples, strategies, shrinking, the real bugs it found in our…

Read article →
Databases & SQL

SQL Pagination Explained: OFFSET vs Keyset, With a Million-Row Test

SQL pagination explained with a million-row test we ran: LIMIT and OFFSET, why deep pages get slow, keyset (cursor) pagination,…

Read article →
Databases & SQL

SQL EXISTS vs IN: Differences, the NOT IN NULL Trap and Performance

SQL EXISTS vs IN explained with queries we ran: how each works, why NOT IN returns no rows when a…

Read article →
Software Development

Python Logging Explained: Levels, Handlers, Formatters and Mistakes to Avoid

Python logging explained with code we ran: levels, basicConfig quirks, named loggers, handlers and formatters, logger.exception, lazy formatting, duplicate logs…

Read article →
Software Development

JavaScript Map vs Object: Key Differences, Pitfalls and a Benchmark

JavaScript Map vs Object explained with code we ran in Node.js: key types, ordering, the prototype trap, JSON, size, WeakMap…

Read article →
Software Development

Python Type Hints Explained: Annotations, mypy and the Errors It Catches

Python type hints explained with a real mypy run: basic annotations, Optional and unions, TypedDict, Literal, Protocol, generics, Callable, strict…

Read article →
Artificial Intelligence

LLM Tokens Explained: How AI Models Read Text, Count Costs and Fill Context Windows

LLM tokens explained with a tokenizer we ran: how text is split, why counts differ by language and tokenizer, context…

Read article →
DevOps

Semantic Versioning Explained: MAJOR.MINOR.PATCH, Ranges and Release Rules

Semantic versioning explained with code we ran: MAJOR.MINOR.PATCH rules, pre-releases, correct version sorting, caret and tilde ranges, 0.x versions, lockfiles…

Read article →
DevOps

Git Reset vs Revert: How to Undo Commits Safely, With a Tested Example

Git reset vs revert explained with a repository we built: soft, mixed and hard reset, revert commits, reverting merges, recovering…

Read article →
Software Testing

The Test Pyramid Explained: Layers, Ratios and When to Break the Shape

The test pyramid explained: unit, integration and end-to-end layers, sensible ratios, the ice cream cone anti-pattern, the testing trophy and…

Read article →
Test Automation

pytest Fixtures Explained: Scope, yield Teardown, conftest.py and Factories

pytest fixtures explained with a suite we ran: how fixtures work, scopes, yield teardown, conftest.py, factory fixtures, parametrized fixtures, built-ins…

Read article →
Databases & SQL

SQL Upsert Explained: INSERT ON CONFLICT, MERGE and the REPLACE Trap

SQL upsert explained with queries we ran: INSERT ON CONFLICT DO UPDATE and DO NOTHING, the excluded row, conditional updates,…

Read article →
Databases & SQL

SQL LIKE Operator Explained: Wildcards, Case Sensitivity and Performance

The SQL LIKE operator explained with queries we ran: % and _ wildcards, escaping, NOT LIKE and NULL, case sensitivity…

Read article →
Artificial Intelligence

AI Hallucinations Explained: Why Language Models Make Things Up and How to Reduce It

AI hallucinations explained: what they are, why language models produce them, common types, how to reduce them with grounding and…

Read article →
Test Automation

Mocking in Python: unittest.mock, patch and the Mistakes That Make Tests Lie

Mocking in Python with unittest.mock, tested: Mock and return_value, side_effect, patching where a name is used, spec and autospec, mocking…

Read article →
Software Testing

Code Coverage Explained: Line vs Branch Coverage and What 100% Really Means

Code coverage explained with a real coverage.py run: line, branch and condition coverage, reading a report, why 100% coverage can…

Read article →
Artificial Intelligence

What Are AI Agents? How They Work, With a Simple Agent Loop You Can Run

What are AI agents? A plain guide to the agent loop, tools, memory and guardrails, with a small Python loop…

Read article →
Test Automation

TDD vs BDD: Key Differences, One Feature Built Both Ways and When to Use Each

TDD vs BDD explained with one discount feature built both ways: red-green-refactor with code we ran, Given-When-Then scenarios, tools, trade-offs…

Read article →
Software Testing

User Acceptance Testing (UAT): Process, Checklist and Real Examples

User acceptance testing explained: who runs it, how it differs from QA, a seven-step process, a UAT test case template,…

Read article →
Artificial Intelligence

What Are Embeddings? Vectors and Cosine Similarity Explained Simply

What are embeddings? A plain-language guide to vectors, cosine similarity and semantic search, with a small example we ran, common…

Read article →
Test Automation

Flaky Tests: What Causes Them and How to Fix Them for Good

Flaky tests explained with demos we ran: the main causes, how to confirm and diagnose one, proper fixes for timing,…

Read article →
Software Testing

Load Testing vs Stress Testing: Differences, Metrics and k6 Examples

Load testing vs stress testing explained: what each proves, spike and soak tests, the metrics that matter, why averages mislead,…

Read article →