gotchasqlMinor
Why does an index scan read more pages than exist in an index?
Viewed 0 times
whyscanreadthanmoreexistdoesindexpages
Problem
I've been trying out running some queries for a testing scenario and I noticed that when doing a full-scan of a nonclustered index, SQL Server reads more pages than actually are in the index.
As you can see from the image below, my query is (a simple one):
and I have an exact covering nonclustered index for those columns.
In Profiler the number of pages read for this is
But when looking at the index details, under Fragmentation, the number of pages for this index is
What is the cause for this difference in pages read (
The index is not fragmented (or appears not to be), so there are no more pages than those
(This is a controlled environment, no inserts and no deletes occurred on the table while taking screenshots for this question)
I have also pasted the plan here.
As you can see from the image below, my query is (a simple one):
select
sometext
, somemoretext
from tbland I have an exact covering nonclustered index for those columns.
In Profiler the number of pages read for this is
22,356 as you can see in the image.But when looking at the index details, under Fragmentation, the number of pages for this index is
22,278.What is the cause for this difference in pages read (
78 to be precise)? Is the number in the Fragmentation section not reliable or is there some other explanation?The index is not fragmented (or appears not to be), so there are no more pages than those
22,278 .. or are there? I wasn't able to find an explanation for this online, on Microsoft sites or otherwise.(This is a controlled environment, no inserts and no deletes occurred on the table while taking screenshots for this question)
I have also pasted the plan here.
Solution
You should check what code is submitted to the server when you open "Fragmentation" (using
And you'll see the following code:
Note the mode: it's
The code returns only 1 row that reflects
Now change the code to use
Here is my repro.
I first look at Fragmentation tab where I find that my
Then I executed the code that I saw in
Then I changed
If your
My SSMS's version is 10.50.6000.34 and my explanation is valid for this version.
SQL Server Profiler)And you'll see the following code:
select partition_number as PartitionNumber,
index_type_desc as IndexType,
index_depth as Depth,
avg_fragmentation_in_percent as AverageFragmentation,
page_count as Pages,
avg_page_space_used_in_percent as AveragePageDensity,
record_count as Rows,
ghost_record_count as GhostRows,
version_ghost_record_count as VersionGhostRows,
min_record_size_in_bytes as MinimumRecordSize,
max_record_size_in_bytes as MaximumRecordSize,
avg_record_size_in_bytes as AverageRecordSize,
forwarded_record_count as ForwardedRecords
from sys.dm_db_index_physical_stats(7, 773577794, 2, NULL, 'SAMPLED')Note the mode: it's
'SAMPLED'.The code returns only 1 row that reflects
page_count of the leaf level of the index.Now change the code to use
'DETAILED' and you'll find missing pages from non-leaf levels.Here is my repro.
I first look at Fragmentation tab where I find that my
ix_include_filler index has 20836 pages.Then I executed the code that I saw in
Profiler, and the code as it is uses "SAMPLED", returns 1 row and shows 20836 pages that we see in "Fragmentation" tab.Then I changed
"SAMPLED" to "DETAILED" and clearly see that these 20836 are only from a leaf level. Level N1 has other 36 pages + a root.If your
SSMS launches different code when you open Fragmentation tab, maybe you should update your question with SSMS version and spy the code it sends by yourself.My SSMS's version is 10.50.6000.34 and my explanation is valid for this version.
Code Snippets
select partition_number as PartitionNumber,
index_type_desc as IndexType,
index_depth as Depth,
avg_fragmentation_in_percent as AverageFragmentation,
page_count as Pages,
avg_page_space_used_in_percent as AveragePageDensity,
record_count as Rows,
ghost_record_count as GhostRows,
version_ghost_record_count as VersionGhostRows,
min_record_size_in_bytes as MinimumRecordSize,
max_record_size_in_bytes as MaximumRecordSize,
avg_record_size_in_bytes as AverageRecordSize,
forwarded_record_count as ForwardedRecords
from sys.dm_db_index_physical_stats(7, 773577794, 2, NULL, 'SAMPLED')Context
StackExchange Database Administrators Q#195269, answer score: 9
Revisions (0)
No revisions yet.