← SQL Server Internals

Buffer Pool Visualizer

▶ DRILL

The Database Is in Memory

SQL Server never touches a data page on disk directly. Every read and every write happens against an 8 KB copy of the page held in a slot in the buffer pool — a large region of RAM that is, on most production servers, the single biggest thing the process owns. Disk is where pages are kept safe; memory is where the database actually runs.

So the first question every query asks of every page it needs is: are you already here?A hit is a logical read — the page is in the pool and comes back at memory speed, on the order of 100 nanoseconds. A miss is a physical read — the page has to be fetched from disk into a free slot first, costing thousands of times more on NVMe and hundreds of thousands more on a spinning disk. The whole art of the buffer pool is keeping the pages you are about to want already resident, so that logical is nearly always the answer.

Buffer Pool ExplorerCold-cache warm-up, LRU-K eviction under a table scan, and read-ahead prefetch.
slowfast
0/16
#Select a scenario and press PLAY to start.
# buffer pool — 12 × 8 KB slots
00—
01—
02—
03—
04—
05—
06—
07—
08—
09—
10—
11—
# I/O stats
logical reads0
physical reads0
read-ahead reads0
# legend
logical read (hit)
physical read (miss)
evict + load
read-ahead prefetch
Pool starts empty. A query reads 8 pages — all physical reads. Same query again: all logical reads, zero disk I/O.

Why Hot Pages Survive a Scan

A naive cache evicts whatever was used least recently. That rule is a disaster for a database, because a single large table scan touches millions of pages exactly once and would sweep your entire working set out of memory on its way through. SQL Server uses LRU-K(specifically LRU-2): instead of the last access, eviction is scored on the K-th most recent access. A page read once — a single-use scan page — has no second reference, so it scores as effectively negative infinity and is reclaimed first. The pages your workload keeps coming back to have a real history of references and stay put. The scan flows through a small pool of slots without disturbing the hot set.

Reads the Query Thread Never Waits For

When the engine notices it is walking pages in order — a range scan down an index, a scan across a heap — it starts issuing read-ahead requests: asynchronous prefetches for the pages it can see coming. The disk I/O still happens, but it happens ahead of the query thread rather than in front of it. By the time the thread asks for the next page, it is already sitting in a slot. A successful read-ahead turns what would have been a physical read into a logical one from the thread's point of view — the latency is real, but it has been hidden behind work the thread was going to do anyway.

The Write Side: Dirty Pages and the Log

Writes are where the pool earns its keep. When a statement modifies a row, SQL Server changes the page in memory and marks it dirty — it does not run to disk. What it does do first, before the transaction can commit, is harden the log recorddescribing the change to the transaction log. This is write-ahead logging: the log is the durable record, so a committed transaction survives a crash even though its dirty data page may still be sitting in RAM, unwritten.

The dirty pages themselves are flushed later, in the background, by two mechanisms.Checkpoint sweeps dirty pages to disk on a schedule, advancing the point the engine would have to recover from and keeping crash-recovery time bounded. Thelazy writer responds to memory pressure — when free slots run low it scans the pool, writes out dirty pages, and returns clean ones to the free list so the next physical read has somewhere to land. Neither one sits in the transaction's path; both exist so that the query thread almost never blocks on a write.

Reading the Pool's Health

The metric people watch is Page Life Expectancy — roughly, how long a page is expected to stay in the pool before it is evicted. It is a proxy for churn: when PLE is falling, pages are being pushed out faster than the workload can reuse them, which usually means the pool is too small for the working set. Ignore the folklore fixed threshold of 300 seconds; judge PLE against your own server's baseline and scale it to how much memory the pool actually has.

TUNING

This is why SET STATISTICS IO reports logical reads, and why that is the number you tune against — not physical reads. Physical reads depend on what happened to be cached when you ran the query; run it twice and they vanish. Logical reads count every page the plan touches regardless of cache state, so cutting them — a better index, a tighter plan, fewer pages visited — is the stable, repeatable win.