In my last article,
I described the concept behind SQL Server index statistics. Today, I will present the real world example from AdventurWorks database. Launch Management Studio and execute the following script
Use AdventureWorks
Go
DBCC SHOW_STATISTICS (‘Sales.SalesOrderDetail’,‘IX_SalesOrderDetail_ProductID’ )
Go
You will get the result similar to this:
The fist resultset tells you about the basic details of statistics collected for the index IX_SalesOrderDetail_ProductI You can check when was the statistics last updated. If it is too old then you need to update the statistics.
Second resultset guides you about the density of frequent values. Frequent value means the value which appeared more than once in the step. The All density considers frequent values and Density considers nonfrequent values only.
Third resultset is actually the most intersting section. This is the histogram of values of the indexed column of the index or the first column of the composit index. Description of its columns is as follows:
Column

Details

RANGE_HI_KEY

Upper bound value of a histogram step i.e. the highest value in the step. The first step is the lowest value for the column in the table.

RANGE_ROWS

Number of rows from the sample that fall within a histogram step, excluding the upper bound. By definition, this must be zero in the first sample.

EQ_ROWS

Number of rows from the sample that are equal in value to the upper bound of the histogram step.

DISTINCT_RANGE_ROWS

Number of distinct values within a histogram step, excluding the upper bound.

AVG_RANGE_ROWS

average number of duplicate values within a histogram step, excluding the upper bound. This is defined as:
(RANGE_ROWS / DISTINCT_RANGE_ROWS
for DISTINCT_RANGE_ROWS > 0)

By using this histogram, SQL Server determines the expected no. of rows to be returned for a given query. For example: in the above if you see the highlighted section, you will noticed that in the 80th step we have
RANGE_HI_KEY=819
RANGE_ROWS=218
EQ_ROWS= 195
Firstly, it means that for range of ProductID>815 and ProductID<819 we will get 218 rows. This can be verified by executing the following query:
Select count(*) from Sales.SalesOrderDetail where ProductID>815 and ProductID<819
Result is 218, which confirms the RANGE_ROWS statistics value
Secondly, it also means that for ProductID=819 we will get 195 rows. This can be verified by executing the following query:
Select count(*) from Sales.SalesOrderDetail where ProductID=819
Result is 195, which confirms the EQ_ROWS statistics value.
I hope by seeing these examples, you have got the good idea how SQL Server forecasts the total number of rows to be returned and how they are used in analyzing the cost of index usage.