Login or Sign Up to become a member!
LessThanDot Sit Logo

LessThanDot

Data Management

Less Than Dot is a community of passionate IT professionals and enthusiasts dedicated to sharing technical knowledge, experience, and assistance. Inside you will find reference materials, interesting technical discussions, and expert tips and commentary. Once you register for an account you will have immediate access to the forums and all past articles and commentaries.

LTD Social Sitings

Lessthandot twitter Lessthandot Linkedin Lessthandot friendfeed Lessthandot facebook Lessthandot rss

Note: Watch for social icons on posts by your favorite authors to follow their postings on these and other social sites.

Your profile

    Search

    XML Feeds

    Google Ads

    « SQL Friday, The Best SQL Server Links Of The Past Week Episode 10An Interview With Kevin Kline About SQL In A Nutshell Third Edition »
    comments

    Most developers know that indexes can help speed up your queries, but what happens if you are getting nice index seeks and the performance is still not acceptable? In some cases, a covering index can improve your performance tremendously. This blog will help you identify what the covering index should be and how to test your query to make sure it is being used.

    In SQL Server Management Studio, you can see the execution plan by pressing CTRL-M and then run your query. With Query Analyzer, use CTRL-K. After you run the query, you will see a new tab for the execution plan.

    There is a 'type' of index that performs better than a clustered index. You can create a covering index. This is more of an idea (there is no syntax for COVERING in SQL). It sometimes helps to think of an index as a separate table. It's not, but for the moment, think of it that way. When you create an index, an object is created in the database that has all of the data in the index. SQL Server can then use this index to speed up your queries. Now, consider a query that only uses a couple of columns in your table. If you create an index that has all of the data from those columns, then there is no reason for the query to use the table (because all of the data is found in the index).

    For example:

    1. Create Table PeopleTest(Id int Identity(1,1), Name VarChar(20), FavoriteColor VarChar(20))
    2.  
    3. Create Clustered Index idx_PeopleTest_Id On PeopleTest(id)
    4.  
    5.  
    6. Insert Into PeopleTest(Name, FavoriteColor) Values('George', 'Orange')
    7. Insert Into PeopleTest(Name, FavoriteColor) Values('John',   'Green')
    8. Insert Into PeopleTest(Name, FavoriteColor) Values('Denis',  'Black')
    Id          Name                 FavoriteColor
    ----------- -------------------- --------------------
    1           George               Orange
    2           John                 Green
    3           Denis                Black

    Now, let's look at some queries.

    1. Select FavoriteColor
    2. From   PeopleTest
    3. Where  Id = 2

    This will return 'Green'. Simple, right. Well… here's what's happening behind the scenes. SQL Server will use the clustered index to quickly locate the row where ID = 2. It will then go to the table to get FavoriteColor. Essentially, there are 2 steps. Locate the row in the index and use it to look up the row in the table.

    Now, add this nonclustered index:

    1. Create nonclustered index idx_PeopleTest_Id_FavoriteColor On PeopleTest(Id, FavoriteColor)

    Notice that there are 2 columns in the index (Id and FavoriteColor). Now, let's run the exact same query and look at the execution plan again.

    1. Select FavoriteColor
    2. From   PeopleTest
    3. Where  Id = 2

    This time, you will see that there is an index seek (instead of clustered index seek). You see, the index has id and favorite color in it, so SQL Server will look up the row in the index and use the FavoriteColor data that it finds. There's no need to use any data from the actual table itself because all the data it needs is in the index.

    Now, let's look at another query.

    1. Select Name, FavoriteColor
    2. From   PeopleTest
    3. Where  Id = 2

    This time, when you run the query, it goes back to a clustered index seek (because that index has less columns and will therefore perform better). There are 3 columns that this query uses. Name, FavoriteColor, and ID. Since there are no indexes that contain all of these column, the best execution plan is to look up the row based on the where clause and then go to the table data to get the Name and FavoriteColor.

    Ok, so you're probably thinking, I can create an index that has all 3 columns to improve performance, right? The answer is, yes, but you need to be careful about it too. If you create this index…

    1. Create nonclustered index idx_PeopleTest_Name_Id_FavoriteColor On PeopleTest(Name, Id, FavoriteColor)

    The index will not be used because the first column in the index is name. This index would need to be scanned (not seeked) to get the row (and the data).

    Think of the index data sorted first by Name, then ID, and finally FavoriteColor, like this…

    Name                 Id          FavoriteColor
    -------------------- ----------- --------------------
    Denis                3           Black
    George               1           Orange
    John                 2           Green

    Since the where clause is looking for Id = 2, it would need to examine every row in the index to find it. For this query, the covering index would look like this:

    1. Create nonclustered index idx_PeopleTest_Id_Name_FavoriteColor On PeopleTest(Id, Name, FavoriteColor)

    Now, when you run the query, you will see an index seek again.

    You need to be careful with indexes though. Having too many indexes on a table will slow down your performance because every insert, update, and delete statement will affect the data in the index too.

    About the Author

    George has been developing software professionally for 19 years, first for the department of defense, and then for various other companies. In 1998, George started his software company, Orbit Software, specializing in School Bus Transportation software. His specialty is refining SQL Server queries to deliver optimal performance.
    Social SitingsTwitterLTD RSS Feed
    InstapaperVote on HN

    8 comments

    Comment from: SQLDenis [Member] Email
    *****
    SQLDenis Nice,

    also since SQL server 2005 you can create an index with included columns

    INCLUDE ( column [ ,... n ] )
    Specifies the non-key columns to be added to the leaf level of the nonclustered index. The nonclustered index can be unique or non-unique.
    02/04/09 @ 13:51
    Comment from: riverguy [Member] Email
    *****
    riverguy Nice article. Would it be correct to assume that you'll still get just the index seek for your last example if you swap out the positions of Name and FavoriteColor in your SELECT statement?
    02/05/09 @ 06:24
    Comment from: George Mastros (gmmastros) [Member]
    George Mastros (gmmastros) @riverguy,

    Yes. You'll still get an index seek (it will still be a covering index) because the order of columns in the select clause does not matter. Only the ordering in the index is important.
    02/05/09 @ 06:33
    Comment from: Erik [Member] Email
    *****
    Erik The order of the columns in the index can be significant if you are commonly specifying additional criteria or sorting by a particular column. Whatever is most often used after the primary criterion (in this case WHERE Id = 2), put it as the next column after Id.

    Analysis of typical usage can be done by running traces done across an entire business cycle, and then compiling and analyzing the data. You can also get additional information in SQL 2005 about underused indexes or missing indexes with sys.dm_db_index_usage_stats, sys.indexes, sys.dm_db_missing_index_group_stats, sys.dm_db_missing_index_groups, and sys.dm_db_missing_index_details. I should blog about these, though my own information comes from reading other folks' blogs.
    02/07/09 @ 15:50
    Comment from: Nathan [Visitor]
    ***--
    Nathan nice post

    Thanks
    Nathan
    http://sqldbsolution.blogspot.com/
    06/04/09 @ 01:06
    Comment from: Naomi Nosonovsky [Member]
    *****
    Naomi Nosonovsky Thanks
    07/31/09 @ 08:28
    Comment from: Sm [Visitor]
    Sm Excellent
    12/02/09 @ 09:09
    Comment from: Jinesh [Visitor]
    Jinesh Nice Article,

    I am reading other articles regading covering index, will get back to you if I have any doubt.


    Regards,
    Jinesh
    10/11/11 @ 03:56

    Leave a comment


    Your email address will not be revealed on this site.

    To mislead the spambots.

    Your URL will be displayed.
    (Line breaks become <br />)
    (Name, email & website)
    (Allow users to contact you through a message form (your email will not be revealed.)