Course contentsShow
← Databases & SQL
Lesson 1259 of 1,95311. NoSQL and Document ModelsFree lesson

Analyzing Write Skew

Detect and prevent race conditions when updating dependent documents.

In this lesson, you will learn how to identify and prevent "write skew," a subtle concurrency anomaly that occurs when two transactions read overlapping sets of data but modify disjoint sets in a way that violates a business invariant.

The Problem: When Isolation Fails

Write skew happens when two concurrent processes perform a check-then-act operation. Unlike a lost update (where two processes modify the same field), in write skew, both processes see the same state, verify that a condition is met, and proceed to modify different objects. Because the modifications are disjoint, standard row-level locking often fails to stop them.

Imagine a "Doctor On-Call" system where at least one doctor must be active. Currently, Alice and Bob are both on-call.

  1. Transaction A reads both doctors, sees two are active, and concludes it is safe to set Alice to "inactive."
  2. Transaction B reads both doctors, sees two are active, and concludes it is safe to set Bob to "inactive."
  3. Both transactions commit. The business invariant—that at least one doctor must be on-call—is now violated.

Detecting and Preventing Write Skew

Detecting write skew requires auditing your application logic for "predicate-based" updates. If your code performs a query, calculates a state, and then performs a write based on that result, you are at risk.

To prevent this, you must upgrade your transaction isolation level or use explicit locking. In many document systems, if strict serializable isolation isn't available, you can use Materialized Conflicts:

// Instead of checking the whole collection, lock a representative document
db.system_state.updateOne(
  { _id: "on_call_config" }, 
  { $inc: { version: 1 } } // Forcing a conflict on a shared object
);

By forcing both processes to update a single "dummy" document or a specific parent document related to the invariant, you force the database to serialize the transactions. The second transaction will either block or fail with a conflict, forcing a retry. By pinning the logic to a shared dependency, you protect the business constraint from being invalidated by concurrent threads.

Key Takeaway: Write skew occurs when concurrent transactions update different records based on the same shared state; prevent it by using materialized conflicts or serializable isolation to force serialization on the underlying business invariant.