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 Advent 2011 Day 20: Indexes with Included ColumnsSQL Advent 2011 Day 18: Table-valued Parameters »
    comments

    In my Are you ready for SQL Server 2012 or are you still partying like it is 1999? post, I wrote about how you should start using SQL Server 2005 and SQL Server 2008 functionality now in order to prepare for SQL Server 2012. I still see tons of code that is written in the pre 2005 style and people still keep using those functions, procs and statements even though SQL Server 2005 and 2008 have much better functionality.

    Today we are going to take a look at Filtered Indexes. A filtered index is an optimized nonclustered index, the filtered index is based on a WHERE clause, thus this index will cover your query if your query has the same WHERE clause

    We are going to create a table and populate it with 52048 rows, 50000 will be null and the rest will be numbered between 0 and 2047.

    1. CREATE TABLE TestFiltered(id INT)
    2. GO
    3.  
    4. --insert numbers between 0 and 2047
    5. INSERT TestFiltered
    6. SELECT number
    7. FROM master..spt_values
    8. WHERE TYPE = 'p'
    9.  
    10.  
    11. -- add 50000 NULLS
    12. INSERT TestFiltered
    13. SELECT TOP 50000 NULL FROM sys.sysobjects s1
    14. CROSS JOIN sys.sysobjects s2
    15. CROSS JOIN sys.sysobjects s3

    Now we will create an identical table

    1. SELECT * INTO TestFiltered2 FROM TestFiltered

    We are adding a simple non clustered index on the table

    1. CREATE NONCLUSTERED INDEX ix_TestFiltered ON TestFiltered(id)
    2. GO

    We are adding a filtered index on the second table, notice that the create statement is almost identical, all we have added really is the WHERE clause

    1. CREATE NONCLUSTERED INDEX ix_TestFiltered2 ON TestFiltered2(id)
    2. WHERE id IS NOT NULL
    3. GO

    Now, let's select all rows where the id is not null, you will get back 2048 rows for each query

    1. SELECT * FROM TestFiltered
    2. WHERE id IS NOT NULL
    3.  
    4.  
    5. SELECT * FROM TestFiltered2
    6. WHERE id IS NOT NULL

    Here is what the execution plan looks like

    As you can see the filtered index performs better. What if we select where it is null instead of not null?

    1. SELECT * FROM TestFiltered
    2. WHERE id IS  NULL
    3.  
    4.  
    5. SELECT * FROM TestFiltered2
    6. WHERE id IS  NULL

    That plan looks a little better also.

    Take a look at IO, even the reads look better

    1. SET STATISTICS IO ON
    2. GO
    3.  
    4. SELECT * FROM TestFiltered
    5. WHERE id IS  NULL
    6.  
    7.  
    8. SELECT * FROM TestFiltered2
    9. WHERE id IS  NULL
    10.  
    11. SET STATISTICS IO  OFF
    12. GO

    (50000 row(s) affected)
    Table 'TestFiltered'. Scan count 1, logical reads 114

    (50000 row(s) affected)
    Table 'TestFiltered2'. Scan count 1, logical reads 84

    How much space does a filtered index like this use compared to a regular index. Look at the storage difference

    1. exec sp_spaceused 'TestFiltered'
    2. exec sp_spaceused 'TestFiltered2'
    name		rows	reserved	data	index_size	unused
    -------------   ------  ----------  -------     -----------       -----
    TestFiltered	52048   1744 KB	     672 KB	952 KB		120 KB
    TestFiltered2	52048    768 KB	     672 KB	 64 KB		32 KB

    As you can see the table with the filtered index is much smaller in size, the index is 14 times smaller

    An index like this is very useful when you have columns that are nullable and a large percentage of the values are NULL, when you run a report in general you want to see the values, a filtered index will be very useful with that.

    Here are some advantages that filtered indexes have over regular indexes according to Books On Line

    Filtered indexes can provide the following advantages over full-table indexes:

    Improved query performance and plan quality

    A well-designed filtered index improves query performance and execution plan quality because it is smaller than a full-table nonclustered index and has filtered statistics. The filtered statistics are more accurate than full-table statistics because they cover only the rows in the filtered index.

    Reduced index maintenance costs

    An index is maintained only when data manipulation language (DML) statements affect the data in the index. A filtered index reduces index maintenance costs compared with a full-table nonclustered index because it is smaller and is only maintained when the data in the index is affected. It is possible to have a large number of filtered indexes, especially when they contain data that is affected infrequently. Similarly, if a filtered index contains only the frequently affected data, the smaller size of the index reduces the cost of updating the statistics.

    Reduced index storage costs

    Creating a filtered index can reduce disk storage for nonclustered indexes when a full-table index is not necessary. You can replace a full-table nonclustered index with multiple filtered indexes without significantly increasing the storage requirements.

    Look up filtered indexes in Book On Line and play around with them to see if they will be beneficial in your database

    That is it for today's post, come back tomorrow to learn about indexes with included columns.

    About the Author

    User bio imageDenis has been working with SQL Server since version 6.5. Although he worked as an ASP/JSP/ColdFusion developer before the dot com bust, he has been working exclusively as a database developer/architect since 2002. In addition to English, Denis is also fluent in Croatian and Dutch, but he can curse in many other languages and dialects (just ask the SQL optimizer) He lives in Princeton, NJ with his wife and three kids.
    Social SitingsTwitterFacebookLinkedInHomePageFlickrLTD RSS Feed
    749 views
    Instapaper

    2 comments

    Comment from: David Forck (thirster42) [Member]
    how/could you do this with an index with includes?
    12/20/11 @ 13:27
    Comment from: SQLDenis [Member] Email
    SQLDenis Example for Books On Line


    CREATE NONCLUSTERED INDEX FIProductAccessories
    ON Production.Product (ProductSubcategoryID, ListPrice)
    Include (Name)
    WHERE ProductSubcategoryID >= 27 AND ProductSubcategoryID <= 36;
    GO
    12/20/11 @ 19:16

    Leave a comment


    Your email address will not be revealed on this site.

    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.)