Database Interview Prep
Transactions and Concurrency

Dirty Read and READ UNCOMMITTED

Reading Writes That Never Happened

LinkedIn Hook

"Your dashboard showed a customer was charged 5,000 dollars. Five seconds later it showed they were not. Nothing crashed. Nothing logged an error. The number just... unhappened."

Welcome to the dirty read -- the oldest, dumbest, and most dangerous read anomaly in transaction processing. One session writes a row inside a transaction, a second session reads that uncommitted value, and then the first session rolls back. The second session is now holding data that, as far as the database is concerned, never existed. It made decisions on a number from a parallel universe.

The SQL standard defines four isolation levels precisely to control this kind of chaos: READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, and SERIALIZABLE. READ UNCOMMITTED is the lowest -- the one that allows dirty reads on paper. MySQL InnoDB actually implements it that way. PostgreSQL refuses. Ask Postgres for READ UNCOMMITTED and it silently upgrades you to READ COMMITTED, because its MVCC engine literally cannot expose uncommitted row versions to other sessions.

That single design decision is one of the reasons Postgres has the reputation it does. You can ask for the dangerous thing, and the database will quietly protect you anyway.

In Lesson 11.3 I break down what a dirty read actually looks like at the row level, why Postgres refuses to ever produce one, why MySQL still does by default in some configurations, and how to demonstrate (or fail to demonstrate) the anomaly in two psql sessions side by side.

Read the full lesson -> [link]

#PostgreSQL #Database #Transactions #IsolationLevels #ACID #InterviewPrep #BackendDevelopment #SQL


Dirty Read and READ UNCOMMITTED thumbnail


What You'll Learn

  • What a dirty read actually is at the row-version level, not just the textbook definition
  • How to set the transaction isolation level in PostgreSQL with SET TRANSACTION ISOLATION LEVEL
  • Why PostgreSQL silently upgrades READ UNCOMMITTED to READ COMMITTED and what that means for portability
  • How MVCC (Multi-Version Concurrency Control) makes dirty reads structurally impossible in Postgres
  • How MySQL InnoDB behaves under the same setting and why its default is REPEATABLE READ
  • A two-session psql demo that proves Postgres never exposes uncommitted writes
  • Real production scenarios where assuming dirty reads are possible leads to broken code

The Restaurant Order Pad Analogy -- Reading a Bill That Was Never Rung Up

Picture two waiters in a busy restaurant sharing one set of paper order pads. Waiter A takes a table's order, writes "2x steak, 1x wine -- 87 dollars" on the pad in pencil, and walks toward the kitchen. Before A reaches the kitchen, the customer changes their mind and cancels everything. A erases the pencil entry. The order never happened.

Now imagine Waiter B, walking past A's pad in the moment between the pencil writing and the eraser, glances down and sees "87 dollars." B walks to the manager and reports today's revenue, including that 87 dollars. The manager updates the daily total. A few minutes later A confesses the cancellation -- but the daily total still reflects the ghost order. Nobody knows where the bad number came from. The books do not balance.

That is a dirty read. Waiter B read a value that was still in pencil -- still inside another transaction, still subject to being erased -- and acted on it as if it were real. The fix is policy: B is not allowed to read pencil. B has to wait until A confirms the order in pen, or moves on to a different table.

Databases face the same problem at machine speed, with thousands of waiters. The "in pencil" state is a row that has been modified inside an open transaction but not yet committed. The "in pen" state is a row that has been committed and is durable. The rule "do not read pencil" is the difference between READ UNCOMMITTED and READ COMMITTED. PostgreSQL goes one step further and refuses to even offer a pencil view to other sessions -- it keeps the pencil version in a private notepad that only the writing session can see, and other sessions only ever read the most recently committed pen version.

+---------------------------------------------------------------+
|           THE DIRTY READ ANOMALY                              |
+---------------------------------------------------------------+
|                                                                |
|   Time    Session A (writer)         Session B (reader)        |
|   ----    -----------------          -----------------         |
|   t1      BEGIN;                                               |
|   t2      UPDATE accounts                                      |
|             SET balance = 0                                    |
|             WHERE id = 42;                                     |
|   t3                              -> SELECT balance            |
|                                       FROM accounts            |
|                                       WHERE id = 42;           |
|   t4                              -> sees balance = 0          |
|                                       (THIS IS DIRTY)          |
|   t5      ROLLBACK;                                            |
|   t6                              -> already acted on 0!       |
|                                                                |
|   Result: Session B made decisions based on a value that,     |
|           at the end of time, never existed in the database.  |
|                                                                |
+---------------------------------------------------------------+

The horror is not just that B read the wrong number. It is that B has no way of knowing it was wrong. There is no error, no log, no flag. The dirty value looks exactly like a clean value. Any code path that branches on the read -- "if balance is zero, freeze the account" -- has now executed real-world side effects on phantom data.

Napkin AI Visual Prompt: "Dark gradient (#0a0f1f -> #111a2e). Two parallel horizontal timelines for Session A (top, cyan #4fc3f7) and Session B (bottom, pink #ff5c8a). Session A timeline shows BEGIN -> UPDATE -> ROLLBACK with the UPDATE highlighted in pink. Session B timeline shows SELECT crossing vertically up to the UPDATE moment with a glowing arrow labeled 'DIRTY READ'. Between the two timelines, a jagged white lightning bolt at the read moment. Below the diagram, a small inset showing a green Postgres elephant with a shield labeled 'MVCC' deflecting the lightning bolt. White monospace labels throughout."


The SQL Standard's Four Isolation Levels (and Where Dirty Reads Live)

The ANSI SQL-92 standard defines four isolation levels, ordered from weakest to strongest. Each level is defined by which read anomalies it permits.

+---------------------------------------------------------------+
|           SQL STANDARD ISOLATION LEVELS                       |
+---------------------------------------------------------------+
|                                                                |
|   Level                Dirty   Non-Repeat.  Phantom            |
|                        Read    Read         Read               |
|   ------------------   -----   ----------   -------            |
|   READ UNCOMMITTED     YES     YES          YES                |
|   READ COMMITTED       no      YES          YES                |
|   REPEATABLE READ      no      no           YES (*)            |
|   SERIALIZABLE         no      no           no                 |
|                                                                |
|   (*) PostgreSQL's REPEATABLE READ also blocks phantoms        |
|       because it uses snapshot isolation, which is stricter    |
|       than the standard requires.                              |
|                                                                |
+---------------------------------------------------------------+

READ UNCOMMITTED is the only level on which dirty reads are allowed by the standard. You ask for it explicitly because you want maximum throughput and you are willing to read garbage. In practice, almost no real application wants this -- and PostgreSQL takes the position that no application should want it.

Setting the Isolation Level in Postgres

PostgreSQL accepts all four level names in the SET TRANSACTION statement, for SQL portability:

-- Set the isolation level for the NEXT transaction in this session.
-- Must be issued before BEGIN or as the first statement after BEGIN.
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- Postgres accepts the syntax but treats READ UNCOMMITTED as
-- READ COMMITTED. There is no warning. The upgrade is silent.
SHOW transaction_isolation;
-- transaction_isolation
-- -----------------------
-- read committed
-- (1 row)
COMMIT;

That's the headline: PostgreSQL has only three real isolation levels -- READ COMMITTED, REPEATABLE READ, and SERIALIZABLE. The fourth name exists only so that code written against the standard does not throw a syntax error.


The Two-Session Demo -- Trying (and Failing) to Catch a Dirty Read in Postgres

Let's actually try to produce a dirty read on Postgres. We need two psql sessions running side by side. Open two terminal windows, both connected to the same database.

Setup

-- Run once in either session to set up the demo table.
DROP TABLE IF EXISTS accounts;
CREATE TABLE accounts (
    id      INT PRIMARY KEY,
    owner   TEXT NOT NULL,
    balance NUMERIC(12, 2) NOT NULL
);

-- Insert one account with a known starting balance.
INSERT INTO accounts (id, owner, balance)
VALUES (42, 'Alice', 1000.00);

The Attempt

-- ============================================================
-- SESSION A (the writer)
-- ============================================================
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- Drain Alice's account inside an open transaction.
-- This row is now "in pencil" -- modified but not committed.
UPDATE accounts SET balance = 0 WHERE id = 42;

-- DO NOT COMMIT YET. Switch to Session B and run its query.
-- Then come back here and ROLLBACK.
-- ============================================================
-- SESSION B (the reader) -- run while Session A is still open
-- ============================================================
BEGIN;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

-- Try to see the uncommitted zero from Session A.
SELECT id, owner, balance FROM accounts WHERE id = 42;

-- Sample output (PostgreSQL):
--  id | owner |  balance
-- ----+-------+----------
--  42 | Alice |  1000.00
-- (1 row)

-- We see 1000.00, NOT 0. Postgres returned the LAST COMMITTED
-- version of the row, completely ignoring Session A's open
-- transaction. Even though we asked for READ UNCOMMITTED,
-- the engine refuses to expose the uncommitted version.
COMMIT;
-- ============================================================
-- BACK IN SESSION A
-- ============================================================
ROLLBACK;

-- Verify the row is unchanged.
SELECT id, owner, balance FROM accounts WHERE id = 42;
--  id | owner |  balance
-- ----+-------+----------
--  42 | Alice |  1000.00
-- (1 row)

The demo is anticlimactic by design. Postgres made the dirty read impossible. Session B never saw the zero. There is no setting, no flag, no compile-time option that would change this behavior.

Why It Cannot Happen -- A Quick MVCC Tour

Postgres uses Multi-Version Concurrency Control. When Session A runs UPDATE accounts SET balance = 0 WHERE id = 42, it does not overwrite the existing row. Instead, it:

  1. Marks the existing row version (balance = 1000.00) with xmax = <A's transaction id>, meaning "deleted by transaction A."
  2. Inserts a brand new row version (balance = 0) with xmin = <A's transaction id>, meaning "created by transaction A."

Both versions now coexist in the table's heap. When Session B runs its SELECT, the executor walks the heap and applies a visibility check on every row version it finds:

+---------------------------------------------------------------+
|           MVCC VISIBILITY CHECK (simplified)                  |
+---------------------------------------------------------------+
|                                                                |
|   For each row version with (xmin, xmax):                      |
|                                                                |
|     1. Was xmin committed before B's snapshot was taken?       |
|        - No  -> INVISIBLE (skip)                               |
|        - Yes -> continue                                       |
|                                                                |
|     2. Is xmax NULL, OR was it rolled back, OR did it commit  |
|        AFTER B's snapshot?                                     |
|        - Yes -> VISIBLE (return this version)                  |
|        - No  -> INVISIBLE (skip)                               |
|                                                                |
|   Session B's snapshot was taken at its first query. At that   |
|   moment, A had not committed. So:                             |
|     - The new (balance = 0) version: xmin = A, NOT committed   |
|       -> step 1 fails -> INVISIBLE                             |
|     - The old (balance = 1000) version: xmin = some old txn,   |
|       committed long ago, xmax = A, NOT committed              |
|       -> step 1 passes, step 2 passes -> VISIBLE               |
|                                                                |
+---------------------------------------------------------------+

The visibility rules literally have no path that returns a row version belonging to an in-flight transaction (other than the session's own writes). There is no code branch that says "if isolation level is READ UNCOMMITTED, also return uncommitted versions." That branch does not exist. The dirty read is structurally impossible, not just policy-disabled.

This is also why SHOW transaction_isolation reports read committed after you ask for read uncommitted: under MVCC, the two are operationally identical. There is no point in pretending otherwise.


Demo 2 -- Watching MVCC Hand You Different Snapshots

Let's prove that the read in Session B is coming from the committed snapshot, not from some lock or wait.

-- ============================================================
-- SESSION A
-- ============================================================
BEGIN;

-- First update: balance from 1000 to 500
UPDATE accounts SET balance = 500 WHERE id = 42;
-- Stop here. Switch to Session B.
-- ============================================================
-- SESSION B
-- ============================================================
BEGIN;
-- Read Alice's balance. This takes B's MVCC snapshot.
SELECT balance FROM accounts WHERE id = 42;
--  balance
-- ---------
--  1000.00
-- (1 row)
-- Still sees 1000 because A has not committed.
-- Note: there is no waiting. The query returns instantly.
-- That is the proof that we are reading the old version,
-- not blocking on a row lock.
-- ============================================================
-- BACK IN SESSION A
-- ============================================================
COMMIT;
-- Now A's update is durable. The new committed version is 500.
-- ============================================================
-- BACK IN SESSION B (still inside its own transaction)
-- ============================================================
SELECT balance FROM accounts WHERE id = 42;
--  balance
-- ---------
--  1000.00   <-- still 1000 in READ COMMITTED? Let's check.
-- (1 row)

-- Wait, that depends! In READ COMMITTED, each STATEMENT gets
-- a fresh snapshot, so B should see 500 now. Let's run it
-- again to be sure:
SELECT balance FROM accounts WHERE id = 42;
--  balance
-- ---------
--   500.00
-- (1 row)
-- There we go. The first re-read happens to use the snapshot
-- from before A committed (depending on exact timing); the
-- next statement-level snapshot picks up A's committed change.
COMMIT;

The key takeaway: B never blocked, and B never saw the in-flight value of 500 before A committed. B saw 1000 (the previous committed version) until A's commit became visible to a fresh statement snapshot. That is READ COMMITTED in action -- and it is exactly what you get whether you asked for READ UNCOMMITTED or READ COMMITTED.


Demo 3 -- The Same Test on MySQL InnoDB

MySQL InnoDB actually honors READ UNCOMMITTED. Here is the same test for contrast.

-- ============================================================
-- MySQL Session A
-- ============================================================
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
UPDATE accounts SET balance = 0 WHERE id = 42;
-- Do not commit. Switch to Session B.
-- ============================================================
-- MySQL Session B
-- ============================================================
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
START TRANSACTION;
SELECT balance FROM accounts WHERE id = 42;
-- Sample output (MySQL InnoDB):
-- +---------+
-- | balance |
-- +---------+
-- |    0.00 |
-- +---------+
-- 1 row in set
-- THERE IT IS. A real dirty read. B is holding 0.00 even
-- though A has not committed.
-- ============================================================
-- MySQL Session A
-- ============================================================
ROLLBACK;
-- Now the update never happened, but Session B already
-- acted on the value 0.00.

This is why MySQL InnoDB defaults to REPEATABLE READ, not READ UNCOMMITTED -- the engine's authors knew that exposing uncommitted data is dangerous, so they shipped a safer default and made you explicitly opt into the unsafe one.

+---------------------------------------------------------------+
|           DIRTY READ BEHAVIOR BY ENGINE                       |
+---------------------------------------------------------------+
|                                                                |
|   Engine          Default Level     READ UNCOMMITTED behaves  |
|                                     as...                      |
|   --------------  ----------------  -----------------------    |
|   PostgreSQL      READ COMMITTED    READ COMMITTED (silent)    |
|   MySQL InnoDB    REPEATABLE READ   READ UNCOMMITTED (real)    |
|   SQL Server      READ COMMITTED    READ UNCOMMITTED (real)    |
|   Oracle          READ COMMITTED    READ COMMITTED (silent)    |
|   SQLite          SERIALIZABLE      not supported              |
|                                                                |
+---------------------------------------------------------------+

Notice the pattern: the MVCC-first databases (Postgres, Oracle, SQLite) cannot or will not produce dirty reads. The lock-and-undo-log databases (MySQL InnoDB, SQL Server) can and will, if you ask. This is one of the deepest behavioral differences between the two architectural families, and it shows up in interview questions constantly.


Demo 4 -- A Realistic "Bug" That Cannot Reproduce on Postgres

Imagine you wrote a fraud-detection job that scans the accounts table looking for accounts that hit zero. On MySQL READ UNCOMMITTED, this job would catch transient zeros from in-flight transactions and freeze accounts that were never actually drained.

-- ============================================================
-- The "fraud monitor" query, run on a schedule
-- ============================================================
SELECT id, owner FROM accounts WHERE balance = 0;

On PostgreSQL, regardless of how many writers are mid-transaction with balance = 0 in their pencil notes, this query will only return accounts whose committed balance is zero. Try it yourself:

-- Session A: simulate a write that will roll back
BEGIN;
UPDATE accounts SET balance = 0 WHERE id = 42;
-- Leave open.
-- Session B: the fraud monitor
SELECT id, owner FROM accounts WHERE balance = 0;
-- Sample output:
--  id | owner
-- ----+-------
-- (0 rows)
-- Alice is NOT flagged, even though her in-pencil balance is 0.
-- Session A:
ROLLBACK;
-- Confirms the write never happened. Fraud monitor was correct.

If you wrote this same job for MySQL with READ UNCOMMITTED, you would get a steady stream of false positives proportional to your write volume. The fact that Postgres never produces this bug is one of the practical reasons to trust its consistency story.


Common Mistakes

1. Assuming SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED does something on Postgres. It does not. Postgres accepts the syntax for portability and silently maps it to READ COMMITTED. If you wrote SQL that depends on dirty reads -- for example, a "live counter" that intentionally reads in-flight values -- it will not work on Postgres at all. Always check SHOW transaction_isolation after setting it if you care.

2. Believing "READ COMMITTED is the lowest level Postgres offers, so it must lock things." The opposite is true. READ COMMITTED in Postgres does not block reads at all -- it serves the previous committed version from the MVCC heap. Readers never wait for writers, and writers never wait for readers. The "no dirty reads" guarantee comes from snapshot visibility, not from locks. Confusing this with SQL Server's lock-based READ COMMITTED (which actually does take shared locks) leads to incorrect mental models and bad performance hypotheses.

3. Trying to "speed up" a slow query by lowering the isolation level. Some developers, when a query is slow, try SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED hoping to skip locking. On Postgres this does literally nothing -- the level is unchanged. On MySQL it can change behavior, but the speed gain is almost always nil because InnoDB's REPEATABLE READ also uses MVCC for reads. The right fix is an index, a query rewrite, or a smaller working set, not a weaker isolation level.

4. Confusing dirty reads with non-repeatable reads. A dirty read is reading an uncommitted value -- one that may never become real. A non-repeatable read is reading the same row twice in one transaction and getting two different committed values because someone else committed between the two reads. Both are read anomalies, but only the first one involves uncommitted data. We cover non-repeatable reads in detail in Lesson 11.4.

5. Writing portable SQL that assumes READ UNCOMMITTED has the same semantics across engines. It does not. The same statement gives you snapshot isolation on Postgres and a true uncommitted read on MySQL InnoDB. If your application logic relies on either behavior, you have an engine-specific bug waiting to surface during a database migration. Either pick an isolation level that behaves identically (READ COMMITTED is the safest bet across all major engines), or fence the engine-specific assumptions with explicit checks.


Interview Questions

1. "What is a dirty read, and can it happen in PostgreSQL?"

A dirty read happens when one transaction reads a row that has been modified by another transaction but not yet committed. If the writing transaction later rolls back, the reader is left holding a value that, from the database's perspective, never existed. In PostgreSQL, dirty reads are impossible regardless of the isolation level you request. PostgreSQL's MVCC engine assigns every row version a creation transaction id (xmin) and a deletion transaction id (xmax), and the visibility rules only return row versions whose creating transaction has already committed before the reader's snapshot was taken. There is no code path in the executor that returns a row version belonging to an in-flight transaction, which is why SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED is silently mapped to READ COMMITTED. The protection is structural, not policy-based.

2. "Why does PostgreSQL accept READ UNCOMMITTED if it does not implement it?"

Pure SQL standard compatibility. The ANSI SQL-92 standard defines four isolation levels and a portable application may issue SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED against any conforming database. If Postgres rejected the syntax, that application would fail with a parse error during a database migration. By accepting the syntax and silently providing a stronger guarantee (READ COMMITTED), Postgres keeps the application running while honoring the spirit of the standard, which is "you must provide at least the guarantees of the level requested." Providing more isolation than asked is always allowed; providing less is not.

3. "How does MySQL InnoDB differ from PostgreSQL on dirty reads, and what is each engine's default isolation level?"

MySQL InnoDB actually implements READ UNCOMMITTED as the SQL standard describes it: a session at that level can read row versions modified by other open transactions. You can demonstrate this with two mysql sessions in a few seconds. PostgreSQL cannot produce this behavior under any setting. The default isolation levels also differ and reflect each engine's philosophy: InnoDB defaults to REPEATABLE READ (a stronger level chosen to protect users from the dangers of READ COMMITTED in a lock-based system), while PostgreSQL defaults to READ COMMITTED (a weaker level whose downsides are mitigated by snapshot isolation). Both defaults are reasonable for their respective architectures.

4. "Walk me through, at the row level, why a dirty read is impossible in Postgres MVCC."

When a transaction T1 updates a row, Postgres does not overwrite the existing row -- it inserts a new row version with xmin = T1 and marks the previous version with xmax = T1. Both versions live in the table's heap simultaneously. When transaction T2 runs a SELECT, it takes a snapshot recording which transaction ids were already committed at that moment. For each candidate row version, T2 checks: is xmin a committed transaction id in my snapshot? If T1 has not committed yet, the new row version's xmin fails this check and the version is invisible. The old row version's xmin is some long-ago committed transaction (so it passes the first check), and its xmax is T1 -- which has not committed -- so the deletion is treated as not yet effective and the old version is visible. T2 returns the old, committed value. The new in-flight value is structurally unreachable.

5. "Are there any legitimate use cases for READ UNCOMMITTED on a database that supports it, like MySQL?"

A few, and they are all narrow. The classic example is approximate aggregates over very large tables -- rough row counts, dashboards that tolerate slightly inconsistent data, monitoring queries that should never block writers. If you are running SELECT COUNT(*) FROM huge_table on MySQL with no index hint and no need for exact correctness, READ UNCOMMITTED can avoid acquiring shared locks and thus avoid contention with writers. Another example is data forensics or debugging, where a DBA explicitly wants to see what other sessions are mid-write. Outside these narrow cases, READ UNCOMMITTED is a footgun and should not be used. On PostgreSQL the question is moot because the level does not exist in practice; you would use a separate replica or a pg_stat_activity query for live observation instead.


Quick Reference -- Cheat Sheet

+---------------------------------------------------------------+
|           DIRTY READ AND READ UNCOMMITTED                     |
+---------------------------------------------------------------+
|                                                                |
|  DEFINITION:                                                   |
|   Dirty read = reading a row modified by another transaction  |
|   that has not committed yet (and may roll back).             |
|                                                                |
|  WHERE IT LIVES IN THE SQL STANDARD:                           |
|   READ UNCOMMITTED is the only level that ALLOWS it.          |
|   READ COMMITTED, REPEATABLE READ, SERIALIZABLE all forbid.   |
|                                                                |
|  POSTGRES BEHAVIOR:                                            |
|   - Accepts SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED  |
|   - Silently treats it as READ COMMITTED                      |
|   - Dirty reads are STRUCTURALLY impossible (MVCC)            |
|   - SHOW transaction_isolation returns 'read committed'       |
|                                                                |
|  MYSQL InnoDB BEHAVIOR:                                        |
|   - READ UNCOMMITTED actually allows dirty reads              |
|   - Default level is REPEATABLE READ (safer)                  |
|                                                                |
|  HOW TO TEST IT:                                               |
|   1. Open two psql / mysql sessions                           |
|   2. A: BEGIN; UPDATE ...; (do not commit)                    |
|   3. B: SELECT the same row                                   |
|   4. A: ROLLBACK                                              |
|   5. Postgres: B saw the OLD value                            |
|      MySQL R.U.: B saw the NEW (rolled-back) value            |
|                                                                |
+---------------------------------------------------------------+

+---------------------------------------------------------------+
|           KEY RULES                                            |
+---------------------------------------------------------------+
|                                                                |
|  1. Postgres has 3 real isolation levels, not 4               |
|  2. READ UNCOMMITTED on Postgres == READ COMMITTED            |
|  3. MVCC visibility rules cannot return in-flight rows        |
|  4. Readers never block writers, writers never block readers  |
|  5. MySQL InnoDB default is REPEATABLE READ, not R.U.         |
|  6. A dirty read leaves NO trace -- no error, no log         |
|  7. Lower isolation does not "speed up" Postgres              |
|  8. Always SHOW transaction_isolation to confirm the level    |
|                                                                |
+---------------------------------------------------------------+
ConceptStandardPostgreSQLMySQL InnoDB
READ UNCOMMITTED allows dirty readsYesNo (mapped to RC)Yes
Default isolation levelundefinedREAD COMMITTEDREPEATABLE READ
Readers block on writersengine-dependentNeverNever (MVCC reads)
Implementation strategyengine-dependentMVCCMVCC + undo log
SHOW transaction_isolation after R.U.n/aread committedread-uncommitted
Dirty reads structurally possibleyesnoyes
Recommended for new appsn/ause READ COMMITTEDuse REPEATABLE READ

Prev: Lesson 11.2 -- ACID Properties Next: Lesson 11.4 -- Non-Repeatable Read and READ COMMITTED


This is Lesson 11.3 of the Database Interview Prep Course -- 12 chapters, 58 lessons.

On this page