| Lesson 4 | Isolation levels |
| Objective | Define isolation levels for transactions |
An isolation level defines how SQL Server protects one transaction from the effects of other concurrent transactions. In real systems, multiple users read and modify the same tables at the same time. Isolation levels specify what kinds of concurrency side effects are allowed (or prevented), and they drive SQL Server’s behavior around locking and row versioning.
The objective of this lesson is to define the isolation levels available in SQL Server and explain the tradeoffs between consistency (correct, predictable results) and concurrency (high throughput with minimal blocking).
Isolation levels are often explained by the anomalies they prevent. The three most commonly discussed are:
SQL Server enforces these guarantees using locks (shared, exclusive, intent, range, etc.) and, in some configurations, row versioning (reading a consistent version of data without blocking writers).
SQL Server supports a spectrum of isolation levels. Higher isolation typically means fewer anomalies but more locking and potential blocking. Lower isolation typically means more concurrency but greater risk of reading inconsistent data.
READ UNCOMMITTED is the lowest isolation level. It allows reading data that another transaction has modified but not committed. This can produce dirty reads and shifting result sets. It is sometimes used for non-critical reporting queries where approximate results are acceptable, but it should be treated cautiously because it can read data that is later rolled back.
READ COMMITTED is SQL Server’s default. A transaction can read only committed data. This prevents dirty reads, but it does not prevent non-repeatable reads or phantoms in general. A read can block (or be blocked by) concurrent writes depending on the workload and database configuration.
Modern note: many SQL Server environments reduce reader/writer blocking by enabling READ_COMMITTED_SNAPSHOT at the database level.
With that option enabled, READ COMMITTED reads may use row versions rather than shared locks, which changes concurrency behavior significantly.
REPEATABLE READ prevents dirty reads and non-repeatable reads by ensuring that rows read by the transaction cannot be modified by other transactions until the current transaction completes. This is typically implemented with stronger locking, which can increase blocking in write-heavy systems. Phantom rows may still appear because new rows can be inserted that match the search predicate.
SERIALIZABLE is the strictest lock-based isolation level. It extends the guarantees of repeatable read by also preventing phantoms. SQL Server accomplishes this by using key-range locking (locking ranges of index keys), effectively forcing concurrent transactions to behave as if they ran one after another for the affected key ranges. This provides the strongest consistency but can reduce concurrency under contention.
SNAPSHOT isolation provides a consistent point-in-time view of data as of the start of the transaction. Reads do not block writes, and
writes do not block reads in the same way as lock-based isolation. Snapshot isolation relies on row versioning and stores older row versions in
tempdb.
Snapshot isolation improves read concurrency, but it introduces different operational considerations:
You change the isolation level for your current session by using SET TRANSACTION ISOLATION LEVEL. The setting applies to subsequent statements
in the session until you change it again or disconnect.
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
BEGIN TRANSACTION;
-- Statements here run under REPEATABLE READ for this session.
COMMIT TRANSACTION;
Common commands include:
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTEDSET TRANSACTION ISOLATION LEVEL READ COMMITTEDSET TRANSACTION ISOLATION LEVEL REPEATABLE READSET TRANSACTION ISOLATION LEVEL SERIALIZABLESET TRANSACTION ISOLATION LEVEL SNAPSHOTIf you plan to use snapshot-based behaviors, you typically enable them at the database level first:
ALTER DATABASE YourDatabaseName SET ALLOW_SNAPSHOT_ISOLATION ON;
ALTER DATABASE YourDatabaseName SET READ_COMMITTED_SNAPSHOT ON;
Important: enabling row versioning changes system behavior and capacity requirements (especially for tempdb), so this is usually
evaluated and rolled out with monitoring rather than enabled casually.
When you begin a transaction, SQL Server records the work in the transaction log and applies concurrency controls so other sessions interact with your work according to their isolation level and your isolation level. While the transaction remains uncommitted:
This is why isolation level selection is both a correctness decision and a performance decision. The “best” level depends on workload: OLTP systems often prefer short transactions with default read committed (sometimes with snapshot semantics), while financial or inventory workflows may require stricter repeatable read or serializable scopes for specific operations.
The next lessons build on these definitions by showing how nested transactions interact with isolation and why correct transaction scoping is essential to avoid blocking and deadlocks.