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

    « MongoDB: How to include and exclude the fields you want in resultsDriving Predictive Analytics »
    comments

    Functions can be very powerful, but used in the wrong place in a query they can show some unexpected behavior.
    In this post I will be using the AdventureWorks2008R2 database and I will query the Sales.SalesOrderHeader to get all the 2006 OrderDates. A query that doesn’t make much sense but will return some interesting results.
    Take the following query:

    1. USE AdventureWorks2008R2;
    2. GO
    3.  
    4. SELECT OrderDate FROM Sales.SalesOrderHeader
    5. WHERE OrderDate BETWEEN '20060101' AND '20061231';
    6. GO

    If we take a look at the execution plan:

    We see that there is a complete scan of the Clustered Index which makes sense since there is no index on the OrderDate column.
    As the Missing Index Hint suggests, create an index on the OrderDate column:

    1. CREATE INDEX IX_SalesOrderHeader_OrderDate
    2.     ON Sales.SalesOrderHeader(OrderDate);
    3. GO

    Executing our first query again in another form:

    1. SELECT OrderDate FROM Sales.SalesOrderHeader
    2. WHERE OrderDate >= '20060101' AND OrderDate <='20061231';
    3. GO

    Results in the following Execution Plan:

    You see that the query is internally translated to SELECT [OrderDate] FROM [Sales].[SalesOrderHeader] WHERE [OrderDate]<=@1 AND [OrderDate]<=@2> just like the first query using the BETWEEN keyword. The big change is in the execution plan. Since we created an index on the OrderDate column, SQL Server is now using an Index Seek on our index to fetch the results.

    Since we are looking for all the dates in 2006, you might want to consider using the YEAR function. The YEAR function returns only the YEAR part of a date(time) value:

    1. SELECT YEAR('20060127 02:15:59')

    Results in

    So the following query should make sense and is more readable then the former 2:

    1. SELECT OrderDate FROM Sales.SalesOrderHeader
    2. WHERE YEAR(OrderDate) = 2006;
    3. GO

    And looking at the result set it makes sense:

    But when we look at the execution plan:

    We see that our index isn’t seeked anymore but gets a complete scan. So instead of searching in some 4K rows, SQL Server is scanning more than 30K of rows. This is because SQL Server is applying the function to all of the rows in our Sales.SalesOrderHeader table before it’s compared to our desired value.

    Conclusion
    Be careful when using functions in the WHERE clause of a query. It’s possible that the function will be applied to all the rows before the filter is applied. Resulting in scans, non used indexes, more I/O, memory consumption and a poor performing query.

    About the Author

    User bio imageAxel started his IT career more than a decade ago. After a few months he was the accidental DBA for the SQL Server 6.5 running the Service Desk application. It didn't took long or Axel started to focus on SQL Server and after another year he became the full-time DBA in a large Belgian datacenter managing the SQL Servers for the hosted customers.It's more than five years now since he switched to consulting and teaching SQL Server. Axel is a Microsoft Certified DBA and Trainer.
    Social SitingsTwitterLinkedInLTD RSS Feed
    1638 views
    InstapaperVote on HN

    No feedback yet

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