Hook: Interviewers love this one because the commands look similar, but one can delete rows, one can empty a table fast, and one can make the table disappear entirely.
Question: What is the difference between DELETE, TRUNCATE, and DROP in SQL?
Answer: DELETE removes rows, usually with a WHERE clause, and keeps the table structure. TRUNCATE removes all rows from a table much faster by clearing the table as a whole, not row by row. DROP removes the table object itself, so the table, its data, and usually its indexes and constraints are gone.
Interview-Ready Answer: I think of DELETE as removing specific rows, TRUNCATE as emptying the whole table quickly, and DROP as deleting the table itself. DELETE is row-based and can use WHERE; TRUNCATE is set-based, much faster, and often resets identity columns; DROP removes the object and all its metadata, so you must recreate it before using it again. One important detail is that behavior varies by database, especially for rollback and identity reset.
DELETE is for removing chosen rows. TRUNCATE is for clearing a table completely. DROP is for removing the table itself.
| Command | Removes | WHERE? | Typical Speed | Table Still Exists? |
|---|---|---|---|---|
| DELETE | Rows | Yes | Slower | Yes |
| TRUNCATE | All rows | No | Very fast | Yes |
| DROP | Table object | No | Very fast | No |
DELETE is generally O(n) in the number of affected rows because every row must be processed. TRUNCATE and DROP are usually close to O(1) with respect to row count because they are mostly metadata operations, though dependency checks and catalog work still cost something. On a table with 10 million rows, DELETE can create huge log volume and replication lag, while TRUNCATE is often finished in milliseconds or a short burst of seconds depending on locks and storage engine.
Locking matters too: DELETE usually allows more concurrency than TRUNCATE, while TRUNCATE and DROP often need stronger table-level locks. That means TRUNCATE can briefly block readers and writers, which surprises people who only think about speed.
TRUNCATE is transactional and can be rolled back inside a transaction; in MySQL, TRUNCATE is implemented more like DROP plus CREATE and causes an implicit commit.DELETE does not usually reset sequence values. TRUNCATE often resets them, but the exact behavior depends on the database and options like RESTART IDENTITY.TRUNCATE can fail if another table references the table, unless you truncate the dependent tables too or use a cascading option supported by the database.DELETE often leaves reusable free space behind rather than immediately shrinking the file, so disk space may not drop right away.Bottom line: if you need selective removal, choose DELETE. If you need a fast full reset, choose TRUNCATE. If you want the table gone entirely, choose DROP.
Imagine a checkout service with a table called session_tokens that stores login tokens for customers. A developer wants to clean up expired test data before a release and reaches for the wrong command. If they use DELETE, the table survives and the app keeps working; if they use TRUNCATE, they empty the table but may also hit foreign key restrictions or briefly block traffic; if they use DROP, the table disappears and the login flow starts failing immediately.
What goes wrong: Someone runs DROP TABLE session_tokens in production because they think it is just a fast cleanup. The next sign-in request throws errors like relation does not exist or table not found, dashboards show spikes in 500s, and support tickets mention users being unable to log in. Recovery means restoring the table from backup or redeploying the migration, which is far more painful than a simple row delete.
-- PostgreSQL demo: DELETE vs TRUNCATE vs DROP
-- This script is safe to rerun because it starts by cleaning up any old tables.
DROP TABLE IF EXISTS demo_orders;
DROP TABLE IF EXISTS demo_customers;
CREATE TEMP TABLE demo_customers (
customer_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
customer_name TEXT NOT NULL
);
CREATE TEMP TABLE demo_orders (
order_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
customer_id INT NOT NULL REFERENCES demo_customers(customer_id),
amount NUMERIC(10,2) NOT NULL
);
INSERT INTO demo_customers (customer_name)
VALUES ('Ava'), ('Ben');
INSERT INTO demo_orders (customer_id, amount)
VALUES
(1, 19.99),
(1, 9.50),
(2, 42.00);
-- DELETE removes only matching rows and keeps the table.
DELETE FROM demo_orders
WHERE amount < 10;
SELECT 'After DELETE' AS step, order_id, customer_id, amount
FROM demo_orders
ORDER BY order_id;
-- A new insert continues the identity sequence; DELETE does not reset it.
INSERT INTO demo_orders (customer_id, amount)
VALUES (2, 25.00);
SELECT 'After INSERT' AS step, order_id, customer_id, amount
FROM demo_orders
ORDER BY order_id;
-- TRUNCATE removes all rows quickly.
-- In PostgreSQL, RESTART IDENTITY makes the reset explicit.
BEGIN;
TRUNCATE TABLE demo_orders RESTART IDENTITY;
SELECT 'After TRUNCATE in transaction' AS step, COUNT(*) AS row_count
FROM demo_orders;
ROLLBACK;
-- PostgreSQL TRUNCATE is transactional, so rollback brings the rows back.
SELECT 'After ROLLBACK' AS step, order_id, customer_id, amount
FROM demo_orders
ORDER BY order_id;
-- Edge case: TRUNCATE can fail on a referenced table because of foreign keys.
DO $$
BEGIN
BEGIN
TRUNCATE TABLE demo_customers;
EXCEPTION
WHEN OTHERS THEN
RAISE NOTICE 'Expected failure: %', SQLERRM;
END;
END $$;
-- Correct fix: truncate dependent tables together.
TRUNCATE TABLE demo_orders, demo_customers;
SELECT 'After TRUNCATE both tables' AS step, COUNT(*) AS customer_rows
FROM demo_customers;
SELECT 'After TRUNCATE both tables' AS step, COUNT(*) AS order_rows
FROM demo_orders;
-- DROP removes the table object itself, so it no longer exists after this.
DROP TABLE demo_orders;
DROP TABLE demo_customers;DELETE be rolled back? Usually yes if you are inside a transaction. It is a normal data change, so the database can undo it before commit.TRUNCATE always reset identity or auto-increment? Not always; it depends on the database. PostgreSQL lets you choose with RESTART IDENTITY, while other systems may reset automatically or behave differently.TRUNCATE is usually the fastest data-removal option, and DROP is also very fast because it removes the object rather than its rows.WHERE with TRUNCATE or DROP? No. Only DELETE supports row filtering with WHERE.DELETE keeps them, because the table still exists. TRUNCATE keeps the table definition, while DROP removes the table and its related objects unless the database handles dependencies differently.TRUNCATE just a faster DELETE? No. It is a different operation with different locking, no row filtering, and different foreign key behavior.DROP only remove the data? No. It removes the table itself, so the schema object is gone and queries against it will fail until it is recreated.DELETE immediately return disk space to the OS? Often no. Many databases keep freed space inside the table file for reuse, and separate maintenance is needed to shrink it physically.DROP when you only meant to clear rows: the fix is to use DELETE or TRUNCATE depending on whether you need a filter.TRUNCATE is always safe and instant: it can be blocked by foreign keys and it takes strong locks.DELETE may be slow on large tables: if you want to remove everything, TRUNCATE is usually the better tool.Memory Hook: DELETE picks items out of the box, TRUNCATE empties the box, and DROP throws the box away.
DELETE = remove selected rows, supports WHERE.TRUNCATE = remove all rows fast, no WHERE.DROP = remove the table object itself.DELETE is usually slower and more row-by-row.TRUNCATE and DROP are usually metadata-heavy, not row-heavy.DELETE.TRUNCATE and DROP.TRUNCATE can fail unless you handle dependencies.