Database Reference
In-Depth Information
Covering Indexes
A
covering index
is a nonclustered index built upon all the columns required to satisfy a SQL query without going to
the heap or the clustered index. If a query encounters an index and does not need to refer to the underlying structures
at all, then the index can be considered a covering index.
For example, in the following
SELECT
statement, irrespective of where the columns are used within the statement,
all the columns (
StateProvinceld
and
PostalCode
) should be included in the nonclustered index to cover the
query fully:
SELECT a.PostalCode
FROM Person.Address AS a
WHERE a.StateProvinceID = 42;
Then all the required data for the query can be obtained from the nonclustered index page, without accessing the
data page. This helps SQL Server save logical and physical reads. If you run the query, you'll get the following I/O and
execution time as well as the execution plan in Figure
9-1
.
Table 'Address'. Scan count 1, logical reads 19
CPU time = 0 ms, elapsed time = 17 ms.
Figure 9-1.
Query without a covering index
Here you have a classic lookup with the
Key Lookup
operator pulling the
PostalCode
data from the clustered
index and joining it with the
Index Seek
operator against the
IX_Address_StateProvinceId
index.
Although you can re-create the index with both key columns, another way to make an index a covering index is
to use the new
INCLUDE
operator. This stores data with the index without changing the structure of the index itself.
Use the following to re-create the index:
CREATE NONCLUSTERED INDEX [IX_Address_StateProvinceID]
ON [Person].[Address] ([StateProvinceID] ASC)
INCLUDE (PostalCode)
WITH (
DROP_EXISTING = ON);
If you rerun the query, the execution plan (Figure
9-2
), I/O, and execution time change.
Table 'Address'. Scan count 1, logical reads 2
CPU time = 0 ms, elapsed time = 14 ms.