Hook: A dirty read is like peeking at a cake while it is still in the oven: you may react to something that gets taken back a moment later.
Question: What is a dirty read in SQL?
Answer: A dirty read happens when one transaction reads data that another transaction has changed but has not committed yet. If the writer later rolls back, the reader used a value that never became permanent. This is a transaction isolation problem, and it can lead to wrong reports, bad decisions, or inconsistent business logic.
Interview-Ready Answer: In SQL, a dirty read is when I read uncommitted data from another transaction. That means I might see a value that later gets rolled back, so my result was never really valid. Dirty reads are allowed only at the weakest isolation level, usually READ UNCOMMITTED, and in practice many systems avoid them because correctness matters more than a tiny bit of speed.
A dirty read is not just a "fast read". It is a read of data that is still in flight inside another transaction. The key word is uncommitted: the writer has not finished the transaction, so the database has not promised that value will survive.
READ UNCOMMITTED.This question checks whether you understand transaction isolation (the rules that keep concurrent transactions from stepping on each other). A strong answer should say that dirty reads are about correctness, not just syntax. They are one of the classic anomalies alongside non-repeatable reads and phantom reads.
| Isolation level | Dirty reads? | Typical note |
|---|---|---|
| READ UNCOMMITTED | Yes | Weakest; fastest, riskiest |
| READ COMMITTED | No | Common default |
| REPEATABLE READ | No | Stable row re-reads |
| SERIALIZABLE | No | Strongest; most blocking |
Engine defaults matter: SQL Server and PostgreSQL default to READ COMMITTED; MySQL InnoDB often defaults to REPEATABLE READ; Oracle uses READ COMMITTED and does not offer true READ UNCOMMITTED. PostgreSQL accepts the syntax READ UNCOMMITTED, but it behaves like READ COMMITTED, so you still do not get a real dirty read there.
There is no meaningful Big-O complexity for the idea itself. The real trade-off is waiting versus risk: a blocked read might wait a few milliseconds or, with a lock wait setting, up to tens of seconds. Dirty reads can return immediately, but that speed comes from skipping the safety check that protects you from seeing rolled-back data.
SUM can become impossible if it includes uncommitted values.NOLOCK in SQL Server is commonly used to request weak reading, but it is not a magic "no waiting ever" switch. Schema locks can still block, and scans can also miss or duplicate rows in some cases.Memory rule: if the other transaction can still hit ROLLBACK, you should not trust what you just read.
Real-World Story: Imagine a checkout service that also feeds a live revenue dashboard. To keep the dashboard responsive during a sale, an engineer adds a weak-read query hint. One payment transaction inserts an order and temporarily updates inventory, but the card gateway later rejects the charge and the transaction rolls back. The dashboard briefly shows extra revenue and reduced stock, then snaps back. Worse, a fraud or fulfillment job that read the same uncommitted row may already have sent an email or started packing a box.
What goes wrong: support tickets explode because users receive receipts for orders that never existed, the warehouse sees mismatched stock counts, and logs show confusing messages like "order processed" followed by "transaction rolled back". The root cause is not the business rule itself; it is trusting data before the database has committed it.
-- Dirty read demo in SQL Server style.
-- Run the setup once, then open two query windows:
-- Session A = writer
-- Session B = reader
IF OBJECT_ID('dbo.accounts', 'U') IS NOT NULL
DROP TABLE dbo.accounts;
CREATE TABLE dbo.accounts (
account_id INT NOT NULL PRIMARY KEY,
balance INT NOT NULL
);
INSERT INTO dbo.accounts (account_id, balance)
VALUES (1, 1000), (2, 500);
-- =========================
-- Session A: start writing
-- =========================
BEGIN TRANSACTION;
UPDATE dbo.accounts
SET balance = balance - 100
WHERE account_id = 1;
-- Do NOT commit yet.
-- At this point the new balance exists only inside Session A.
-- =========================
-- Session B: read weakly
-- =========================
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT account_id, balance
FROM dbo.accounts
WHERE account_id = 1;
-- If Session A is still open, this can return 900.
-- That value is dirty because it can still disappear.
-- Safer read: this waits for committed data instead of trusting in-flight changes.
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT account_id, balance
FROM dbo.accounts
WHERE account_id = 1;
-- =========================
-- Back to Session A
-- =========================
ROLLBACK TRANSACTION;
-- After the rollback, the true committed value is still 1000.
-- The earlier 900 was never durable, so any logic that acted on it was wrong.
-- Edge case reminder:
-- READ UNCOMMITTED does not guarantee zero blocking in every engine.
-- Some systems still take schema locks, and some databases treat the level differently.Follow-up & Tricky Questions:
READ COMMITTED or stronger isolation, or use row-versioning features where the database provides them. The practical answer is: do not trade correctness for a tiny reduction in wait time unless the data is truly disposable.READ UNCOMMITTED is the standard level associated with dirty reads. Some databases expose it directly; others accept the syntax but map it to a safer behavior.NOLOCK the same as dirty reads? In SQL Server, NOLOCK means read with READ UNCOMMITTED semantics, so it can allow dirty reads. But it is not a guarantee that the query will never block, and it can also return inconsistent scan results.READ UNCOMMITTED, but it treats it like READ COMMITTED, so you do not get true dirty reads.READ UNCOMMITTED mean no locks at all? No. That is a common trap. It means the session is willing to read without honoring many data locks, but the engine can still use or wait on other internal locks such as schema locks.Common Mistakes:
READ UNCOMMITTED is the default everywhere. Correction: Defaults differ by engine, and many systems do not truly expose dirty reads by default.NOLOCK removes all blocking and all problems. Correction: It can still block on non-data locks and can return inconsistent results.Memory Hook: Half-baked cake. If you slice it before it is baked, you may describe a cake that never really existed. Dirty reads are the database version of that mistake.
Cheat Sheet:
READ UNCOMMITTED, permits it.READ COMMITTED or stronger.NOLOCK can allow dirty reads, but it is not a free lunch.Practice Tasks:
READ COMMITTED and observe that the unsafe value is no longer acceptable.READ UNCOMMITTED is truly supported.