Chapter 08 · Storage Engine Internals: Pages, Extents, Heaps, B-Trees, and Transaction Log

Clustered Indexes, Nonclustered Indexes, Row Locators, and Page Splits

Connect clustered and nonclustered B+ trees to row locators, page splits, density, fragmentation, and sequential-key contention.

Advanced125–165 minutesB+ tree + page-split labSQL Server 2025 CU7 · 17.0.4065.4Compatibility 170 · Developer/ExpressLast reviewed: August 2026

Learning outcomes

ServiceHub now needs both fast point lookups and chronological operational scans. That requires a precise model of rowstore indexes. SQL Server documentation often says “B-tree”; rowstore indexes are implemented as a B+ tree: nonleaf levels guide navigation and the leaf level contains either the clustered data rows or nonclustered index rows. This lesson connects that structure to row locators, splits, density, fragmentation, and the separate problem of last-page latch contention.

01

Explain clustered and nonclustered B+ tree leaf semantics.

02

Predict the nonclustered row locator for heap versus clustered base storage.

03

Measure page density and logical fragmentation without using thresholds as universal policy.

04

Relate leaf page allocations to page splits using operational DMV evidence.

05

Separate random middle-page splits from sequential-key last-page contention.

1. The clustered leaf is the table

In a rowstore clustered index, the leaf level contains the full data rows ordered by the clustering key. A nonclustered index has its own ordered leaf rows containing its keys, included columns, and a row locator. If the base object is clustered, the row locator is the clustering key; if the base is a heap, the locator is a RID. That is why a wide clustering key can silently widen every nonclustered index.

sql · build a clustered ServiceHub probe and nonclustered access path
USE ServiceHubLab;GOIF SCHEMA_ID(N'lab08') IS NULL EXEC(N'CREATE SCHEMA lab08 AUTHORIZATION dbo;');DROP TABLE IF EXISTS lab08.WorkOrderIndexProbe;CREATE TABLE lab08.WorkOrderIndexProbe(  work_order_id bigint NOT NULL,  opened_at datetime2(3) NOT NULL,  status varchar(20) NOT NULL,  customer_id int NOT NULL,  summary varchar(500) NOT NULL,  CONSTRAINT PK_WorkOrderIndexProbe    PRIMARY KEY CLUSTERED(work_order_id));CREATE INDEX IX_WorkOrderIndexProbe_StatusOpenedON lab08.WorkOrderIndexProbe(status,opened_at)INCLUDE(customer_id);GO

2. Populate enough rows to make the tree visible

Very small indexes can be a single page, so a B+ tree lesson needs enough rows to create multiple pages. The data generator is deterministic and local; it is not a benchmark.

sql · populate deterministic rows and inspect tree levels
;WITH n AS( SELECT TOP (20000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n FROM sys.all_objects a CROSS JOIN sys.all_objects b)INSERT lab08.WorkOrderIndexProbe(work_order_id,opened_at,status,customer_id,summary)SELECT n,       DATEADD(minute,n,'2026-01-01T00:00:00'),       CASE WHEN n%7=0 THEN 'ESCALATED' ELSE 'OPEN' END,       1+n%1000,       REPLICATE('s',120)FROM n;GOSELECT i.name,ps.index_level,ps.index_depth,ps.page_count,       ps.avg_page_space_used_in_percent,       ps.avg_fragmentation_in_percentFROM sys.indexes AS iCROSS APPLY sys.dm_db_index_physical_stats (DB_ID(),OBJECT_ID(N'lab08.WorkOrderIndexProbe'),i.index_id,NULL,'DETAILED') AS psWHERE i.object_id=OBJECT_ID(N'lab08.WorkOrderIndexProbe')ORDER BY i.index_id,ps.index_level DESC;GO

Expect leaf rows at index_level=0. Higher levels appear as the tree grows. The exact page count, depth, density, and fragmentation are local observations.

3. Page splits, page density, and fragmentation are related but not identical

A page split occurs when SQL Server needs room in a B+ tree page and must allocate/reorganize pages. Mid-tree splits can create logical fragmentation and extra log/I/O work. Page density asks how full pages are; logical fragmentation asks how out-of-order leaf pages are relative to logical key order. A low fill factor intentionally lowers density, which can reduce some middle-page splits but increases the number of pages that must be cached and read.

The operational DMV exposes leaf_allocation_count; for an index, Microsoft documents a leaf page allocation as corresponding to a page split. Counters are cumulative and reset-sensitive, so take a before/after delta for a controlled lab.

sql · measure split-related operational counters around random-key inserts
SELECT leaf_allocation_count,nonleaf_allocation_count,       leaf_page_merge_count,range_scan_count,singleton_lookup_countFROM sys.dm_db_index_operational_stats (DB_ID(),OBJECT_ID(N'lab08.WorkOrderIndexProbe'),1,NULL);GO-- Create a separate random-GUID clustered structure for split observation.DROP TABLE IF EXISTS lab08.RandomKeyProbe;CREATE TABLE lab08.RandomKeyProbe(  id uniqueidentifier NOT NULL DEFAULT NEWID(),  payload char(300) NOT NULL DEFAULT REPLICATE('x',300),  CONSTRAINT PK_RandomKeyProbe PRIMARY KEY CLUSTERED(id));INSERT lab08.RandomKeyProbe DEFAULT VALUES;GO 2000SELECT leaf_allocation_count,nonleaf_allocation_countFROM sys.dm_db_index_operational_stats (DB_ID(),OBJECT_ID(N'lab08.RandomKeyProbe'),1,NULL);SELECT page_count,avg_page_space_used_in_percent,avg_fragmentation_in_percentFROM sys.dm_db_index_physical_stats (DB_ID(),OBJECT_ID(N'lab08.RandomKeyProbe'),1,NULL,'DETAILED')WHERE index_level=0;GO

GO 2000 is a client-utility repeat count supported by tools such as SSMS/sqlcmd, not T-SQL sent to the engine. If your client does not support repeat counts, use a set-based row generator instead.

4. Do not use fill factor to solve a different problem

Reducing fill factor reserves space on leaf pages when an index is built/rebuilt. Microsoft warns that unnecessarily low fill factor increases storage, memory, and I/O. It is most relevant when inserts are distributed into already-existing key ranges. Sequential inserts usually target the right edge; leaving empty space throughout earlier pages does not directly solve a hot last page.

Last-page contention is a latch-concurrency problem commonly visible as PAGELATCH_EX waits on a sequential-key index under high insert concurrency. SQL Server 2019+ offers OPTIMIZE_FOR_SEQUENTIAL_KEY as one option for eligible workloads. That is separate from logical fragmentation and must be diagnosed from waits and concurrency evidence.

sql · show index options without prescribing a universal value
SELECT name,fill_factor,optimize_for_sequential_key,is_disabledFROM sys.indexesWHERE object_id=OBJECT_ID(N'lab08.WorkOrderIndexProbe');GO-- Example only after proving sequential-key latch contention:-- ALTER INDEX PK_WorkOrderIndexProbe-- ON lab08.WorkOrderIndexProbe-- SET (OPTIMIZE_FOR_SEQUENTIAL_KEY = ON);GO
Wrong approach

“Fragmentation above X% means rebuild, and use fill factor 80 everywhere” ignores object size, page density, storage latency, scan patterns, write rate, maintenance cost, and whether fragmentation is even causal. Chapter 09 will turn these metrics into an index portfolio process rather than a magic threshold.

5. Production judgment and cleanup

Use physical stats to describe current structure and operational stats to describe cumulative activity. Correlate both with query plans, waits, I/O, and business latency. Avoid rebuild churn on tiny objects. Treat OPTIMIZE_FOR_SEQUENTIAL_KEY as a targeted concurrency feature, not a default checkbox. Rebuilds and fill-factor changes can be logged, CPU/I/O intensive, and edition/version-sensitive when online/resumable options are involved.

sql · cleanup index probes
DROP TABLE IF EXISTS lab08.RandomKeyProbe;DROP TABLE IF EXISTS lab08.WorkOrderIndexProbe;GO

Check your understanding

  1. What is stored at the leaf of a clustered rowstore index?
  2. What row locator does a nonclustered index use on a clustered table?
  3. Does low page density mean the same thing as logical fragmentation?
  4. What does leaf_allocation_count represent for an index?
  5. What wait commonly signals last-page latch contention?
Review the answers

The full base-table data rows ordered by the clustering key.

The clustering key.

No. Density is page fullness; logical fragmentation is leaf-page ordering relative to key order.

Cumulative leaf page allocations; Microsoft documents an index page allocation as corresponding to a page split.

PAGELATCH_EX, after confirming the contended resource is the hot index page.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.