Getting Started with Adobe After Effects - Part 6: Motion Blur


Upload Image Close it
Select File

Browse by Tags · View All
SQL Server 2008 126
SQL Server 2005 109
TSQL Tips n Tricks 80
Performance Tuning 57
SQL Server 2012 48
SQL Server Basics 24
Sql Server Management 21
SSMS 21
Index 18
SQL Server Denali 13

Archive · View All
March 2011 24
December 2010 23
January 2011 22
May 2011 17
February 2011 16
April 2011 16
July 2012 12
August 2011 9
September 2012 8
August 2012 8

SQL Server: Short Code Doesn’t Mean Smart Code

May 10 2011 1:49PM by aasim abdullah   

Recently a blog reader shared an interesting thing. This mail was basically in response to my early post Why to Avoid TRIM functions in WHERE and JOIN clauses,  where we have discussed, that why we should avoid functions (user defined or system) in where clause columns, because these functions in WHERE, JOIN and GROUP  clauses mislead query optimizer for proper index selection and ultimately results in poor query performance.

Blog reader asked that he tried to remove functions from WHERE clause of all the queries but few queries where date was involve, was hard to correct and after asking at some forum he got a solution and now his code is shorter and quicker.

Actual query was something like as following:

Use AdventureWorks
Go
DECLARE @FindDate DATETIME
SET @FindDate = '2005/09/12 12:00:00'
SELECT *
FROM Purchasing.PurchaseOrderDetail
WHERE CAST(CONVERT(VARCHAR(30), ModifiedDate, 101) AS DATETIME) = CAST(CONVERT(VARCHAR(30), @FindDate, 101) AS DATETIME)

It’s an everyday query, where records from “Purchasing.PurchaseOrderDetail” table are required but where modifieddate column values are equal to given parameter (date). But comparison should be based on date only and time portion should be ignored.

Modified smart query :

SELECT *
FROM Purchasing.PurchaseOrderDetail
WHERE DATEDIFF(DD,ModifiedDate,@FindDate) = 0

Though new query is shorter, but is it quick? Let’s checkout input/output statistics, query time and execution plan for both quires.

WHEREcluaseFunctions1

Table 'PurchaseOrderDetail'. Scan count 1, logical reads 66, physical reads 0

CPU time = 0 ms,  elapsed time = 11 ms.

WHEREcluaseFunctions2

Table 'PurchaseOrderDetail'. Scan count 1, logical reads 66, physical reads 0

CPU time = 0 ms,  elapsed time = 9 ms

Though second query looks more smart but if we ignore minor difference of query elapsed time, both query are almost same as both queries are using clustered index scan and have same value of logical reads. Because problem still exists i.e. Function on WHERE clause columns. For best query performance we have to get rid of this DATEDIFF function too. Here is a better version, as per performance and not the code because our first priority should be performance.

SELECT *
FROM Purchasing.PurchaseOrderDetail
WHERE ModifiedDate >= CAST(
CONVERT(VARCHAR(30), @FindDate, 101) AS DATETIME)
AND ModifiedDate  <= DATEADD(SS, 86399,
CAST(CONVERT(VARCHAR(30), @FindDate, 101) AS DATETIME))

Query code is even more lengthy then first version but what about performance, lets check out input/output stats with query time.

WHEREcluaseFunctions3

Table 'PurchaseOrderDetail'. Scan count 1, logical reads 4, physical reads 0

CPU time = 0 ms,  elapsed time = 1 ms.

From execution plan, it’s clear that after removing functions from modifieddate column (used in WHERE clause), query optimizer selected proper non clustered index, which searched only 4 pages for result and finally query performance is increased.

Tags: SQL Server 2008, Performance Tuning, #tsql, #BI, #SQL Server, brh, TSQL Tips, SQL Server 2005,


aasim abdullah
23 · 7% · 2372
0
Liked
 
0
Lifesaver
 
0
Refreshed
 
0
Learned
 
0
Incorrect



Submit

12  Comments  

  • another interesting post , thanks dude now I have become permanent subscriber of your SQL articles.great job.

    JP
    How HashMap works in Java

    commented on May 11 2011 1:35PM
    Javin Paul
    2270 · 0% · 5
  • Would using BETWEEN be cleaner and just as fast?

    commented on May 12 2011 12:48AM
    Henry Ho
    2893 · 0% · 2
  • I think you meant to use "BETWEEN" instead of "=" in the final version.

    However, BETWEEN (due to it's inclusive-nature) potentially will make you miss entries that are in the last 999 ms of the day (**))

    Hence I would rather use the folllowing, which will be just as good performance wise :

    SELECT *
      FROM Purchasing.PurchaseOrderDetail
     WHERE ModifiedDate >=                Convert(datetime, CONVERT(varchar(30), @FindDate, 101), 101)
       AND ModifiedDate < DATEADD(day, 1, Convert(datetime, CONVERT(varchar(30), @FindDate, 101), 101))
    

    PS: totally off-topic, but I've never seen anyone use CAST() and Convert() "intermixed" =) Personally I would suggest to always use Convert() as it allows you to specify the format in both directions.

    (**: yes, I know, not exactly true do the 3ms granularity of the datetime datatype but if you knew that I'm sure you'll also catch my drift =)

    my 2 cents. Roby

    commented on Jun 10 2011 5:00AM
    Roby Van Hoye
    219 · 1% · 207
  • I don't have AdventureWorks database to try this on, but I think it would be faster to do the date functions outside of the query. Like this:

    
    DECLARE @FindDate   DATETIME
        , @StartDate	DATETIME
        , @EndDate		DATETIME 
    
    SET @FindDate = '2005/09/12 12:00:00'
    SET @StartDate = DATEADD(dd,0, DATEDIFF(dd,0,@FindDate)) 
    SET @EndDate = DATEADD(dd, 1, @StartDate)
    
    SELECT *
    FROM Purchasing.PurchaseOrderDetail
    WHERE ModifiedDate >= @StartDate
        AND ModifiedDate < @EndDate 
    
    commented on Jun 10 2011 7:39AM
    glesser
    1554 · 0% · 12
  • I'm testing these scenarios and seeing no difference between any of the queries. Even the last query in the article that uses two equal comparisons instead of a between, all have 66 logical reads. Personally, I would have gone with the solution that glesser posted above. But after looking at the CPU and Elapsed time I may be changing my mind.

    commented on Jun 10 2011 9:41AM
    Eric
    255 · 1% · 172
  • usually i would like to avoid, "cast" and "convert" in datetime comparisions. Suppose, we can write that expression like below..

    Where ModifiedDate >= DATEADD(dd,datediff(dd,0,@FindDate)),0) and ModifiedDate <  DATEADD(dd,datediff(dd,0,@FindDate),1)
    
    commented on Jun 10 2011 10:04AM
    Ramireddy
    2 · 41% · 12972
  • I like this concept very much. Yes, when i am a beginner, i used to code for shorter ways,even if there is more better ways in terms of performance.

    One common scenario is, some times we will pass comma-seperated values, and will find the rows with those values in tables. I used to use charindex() function previously.

    where charindex(',' + ColName + ',' , ',' + @Vals + ',') > 0

    However, this is not elegant way, If colName has index, it won't use that index.

    The better way is by using split function, split that @vals, and then join with that table. This is long. But is more elegant and will gives better performance.....

    commented on Jun 10 2011 10:08AM
    Ramireddy
    2 · 41% · 12972
  • @glesser : doing the "conversion to midnight" outside the query won't make much of a difference performance-wise in this case as the Query Optimizer will recognize this as "a function on a constant being just another constant' and act accordingly. But I agree that doing it outside of the query is good practice and makes things more readable indeed, especially as you've named them @Start and @End.

    BTW : I know that abusing Convert() for the sake of stripping the hours/minutes/seconds/ms from a datetime value is, well, wrong =) But I didn't want to change the original query on any other element than the one I was trying to point out. That said, I had no idea about the DateAdd(dd, 0, DateDiff(dd, 0, @x)), I always stripped hours, minutes, seconds & ms one by one, this is so much cleaner, nice ! Sometimes Shorter is smarter =P

    commented on Jun 10 2011 2:31PM
    Roby Van Hoye
    219 · 1% · 207
  • o_lander : Possibly you don't have index on "ModifiedDate", create a non clustered index on said column and then execute all three quires. Core theme is that you must avoid function on left side of your WHERE condition, because function will mislead query analyzer and proper index will not be used and resultant query will perform slow.

    commented on Jun 11 2011 12:59AM
    aasim abdullah
    23 · 7% · 2372
  • Very good concept. Yes, moving the application of the function from the value being compared to the value being compared with (i.e. from the LVALUE to the RVALUE) would make a difference.

    Jacob Sebastian has high-lighted this during his session in TechEd 2011. Of course he was trying to emphasize the importance of choosing the right data-types and the impact of functions on performance of a query (Read summary here: http://beyondrelational.com/blogs/nakul/archive/2011/04/06/t-sql-worst-practices-a-compilation-from-jacob-s-session-at-tech-ed-2011-part-02-practices-that-affect-performance.aspx)

    Anyway, coming to the problem at hand, I would avoid using CAST & CONVERT as far as possible when working dates - just as RamiReddy suggests. In my opinion, CAST & CONVERT are for persentation, and must be used when returning data back to the calling application - not during business logic computation (that's not to say that they are not absolutely essential sometimes). When working with scalar values, I would prefer the approach suggested by @glesser.

    At the end I would say that essentially, its all about how best we can convert our scans to seeks - and that is very well illustrated by this post.

    Thanks & Regards,

    Nakul Vachhrajani

    http://beyondrelational.com/blogs/nakul/default.aspx

    Be Courteous. Drive responsibly.

    commented on Jun 13 2011 12:02PM
    Nakul Vachhrajani
    4 · 33% · 10575
  • i prefer this

    AND ModifiedDate < DATEADD(d, 1, CAST(CONVERT(VARCHAR(30), @FindDate, 101) AS DATETIME))

    over this

    AND ModifiedDate <= DATEADD(SS, 86399, CAST(CONVERT(VARCHAR(30), @FindDate, 101) AS DATETIME))

    You should avoid using seconds because datetime data type is accurate upto milliseconds and datetime2 datatype is accurate upto microseconds. Use day for simplicity and to avoid confusion.

    Regards,
    Syed Muhammad Yasir

    commented on Jul 5 2012 12:30PM
    Anonymous
    248 · 1% · 178
  • I like the comment above.

    Regards,
    Muntazer Mehdi

    commented on Jul 5 2012 12:30PM
    Anonymous
    248 · 1% · 178

Your Comment


Sign Up or Login to post a comment.

    Copyright © Rivera Informatic Private Ltd Contact us      Privacy Policy      Terms of use      Report Abuse      Advertising      [ZULU1097]