This is a question that came up this morning during our IE1 class that I thought would make an interesting blog post as there are some twists to the answer.
The first 8 pages that are allocated to an allocation unit are mixed pages from mixed extents, unless trace flag 1118 is enabled.
See the following blog posts for more info:
- Inside the Storage Engine: IAM pages, IAM chains, and allocation units
- Inside the Storage Engine: Anatomy of an extent
- Misconceptions around TF 1118
Assuming that mixed pages are not disabled with trace flag 1118, does an index rebuild remove all mixed pages or not?
Let’s investigate. First I’ll create a clustered index with 1,000 data pages:
CREATE TABLE [MixedTest] ([c1] BIGINT IDENTITY, [c2] CHAR (8000) DEFAULT 'a'); CREATE CLUSTERED INDEX [MixedTest_CL] ON [MixedTest] ([c1]); SET NOCOUNT ON; GO INSERT INTO [MixedTest] DEFAULT VALUES; GO 1000
And then make sure that we have mixed pages be examining the first IAM page in the clustered index’s IAM chain. You can get the sp_AllocationMetadata proc here.
EXEC [sp_AllocationMetadata] N'MixedTest'; GO
Object Name Index ID Alloc Unit ID Alloc Unit Type First Page Root Page First IAM Page ------------ --------- ------------------ ---------------- ----------- ---------- --------------- MixedTest 1 72057594046185472 IN_ROW_DATA (1:987) (1:1732) (1:988)
DBCC TRACEON (3604); DBCC PAGE (N'master', 1, 988, 3); GO
(I’m just including the relevant portion of the DBCC PAGE output here…)
<snip> IAM: Single Page Allocations @0x00000000227EA08E Slot 0 = (1:987) Slot 1 = (1:989) Slot 2 = (1:990) Slot 3 = (1:991) Slot 4 = (1:1816) Slot 5 = (1:1817) Slot 6 = (1:1818) Slot 7 = (1:1819) <snip>
Now I’ll do an offline index rebuild of the clustered index, and look again at the IAM page contents (assume I’m running the proc and DBCC PAGE after the rebuild):
ALTER INDEX [MixedTest_CL] ON [MixedTest] REBUILD; GO
<snip> IAM: Single Page Allocations @0x0000000023B0A08E Slot 0 = (1:1820) Slot 1 = (1:446) Slot 2 = (1:1032) Slot 3 = (0:0) Slot 4 = (1:1035) Slot 5 = (1:1034) Slot 6 = (1:1037) Slot 7 = (1:1036) <snip>
So the answer is no, an index rebuild does not remove mixed page allocations. Only trace flag 1118 does that.
But this is interesting – there are only 7 mixed pages in the singe-page slot array above. What happened? The answer is that the offline index rebuild ran in parallel, with each thread building a partial index, and then these are stitched together. The ‘stitching together’ operation will cause some of the non-leaf index pages to be deallocated as their contents are merged together. This explains the deallocated page that was originally tracked by entry 3 in the slot array.
Let’s try an offline index rebuild that forces a serial plan.
ALTER INDEX [MixedTest_CL] ON [MixedTest] REBUILD WITH (MAXDOP = 1); GO
<snip> IAM: Single Page Allocations @0x0000000023B0A08E Slot 0 = (1:1822) Slot 1 = (1:1823) Slot 2 = (1:291) Slot 3 = (1:292) Slot 4 = (0:0) Slot 5 = (0:0) Slot 6 = (0:0) Slot 7 = (0:0) <snip>
In this case there is only one index (i.e. no parallel mini indexes) being built so there are no pages being deallocated in the new index as there is no stitching operation. But why aren’t there 8 mixed pages? This is because during the build phase of the new index, the leaf-level pages are taken from bulk-allocated dedicated extents, regardless of the recovery model in use. The mixed pages are non-leaf index pages (which you can prove to yourself using DBCC PAGE).
For parallel and single-threaded online index operations, the same two patterns occur as for offline index rebuilds, even though the algorithm is slightly different.