views:

284

answers:

6

Say for instance I'm joining on a number table to perform some operation between two dates in a subquery, like so:

select n
      ,(select avg(col1)
          from table1
         where timestamp between dateadd(minute, 15*n, @ArbitraryDate) 
                             and dateadd(minute, 15*(n+1), @ArbitraryDate))
  from numbers
 where n < 1200

Would the query perform better if I, say, constructed the date from concatenating varchars than using the dateadd function?

+3  A: 

I would NOT go with concatenating varchars.

DateAdd will def be better performace than string contatenation, and casting to DATETIME.

As always, you best bet would be to profile the 2 options, and determine the best result, as no DB is specified.

astander
What's the reason for this?
hypoxide
+4  A: 

Be careful with between and dates, take a look at How Does Between Work With Dates In SQL Server?

I once optmized a query to run from over 24 hours to 36 seconds. Just don't use date functions or conversions on the column , see here: Only In A Database Can You Get 1000% + Improvement By Changing A Few Lines Of Code

to see what query performs better, execute both queries and look at execution plans, you can also use statistics io and statistics time to get how many reads and the time it took to execute the queries

SQLMenace
Thanks for the heads up on "between". I see I would be getting some overlap.
hypoxide
+2  A: 

As long as your predicate calculations do not include references to the columns of the table you're querying, your approach shouldn't matter either way (go for clarity).

If you were to include something from Table1 in the calculation, though, I'd watch out for table scans or covering index scans as it may no longer be sargable.

In any case, check (or post!) the execution plan to confirm.

Michael Haren
+2  A: 

Why would you ever use a correlated subquery to begin with? That's going to slow you up far more than dateadd. They are like cursors, they work row by row. Will something like this work?

 select n.n , avgcol1   
    from numbers n 
    left outer join  
        (
        select avg(col1) as avgcol1, n
        from table1 
        where timestamp between dateadd(minute, 15*n, @ArbitraryDate)  
           and dateadd(minute, 15*(n+1), @ArbitraryDate)
        Group by n
        ) t
     on n.n = t.n
    where n < 1200 
HLGEM
That's a good idea. The problem is that table1 is not enumerated (or necessarily enumerable).
hypoxide
I'm kicking myself for not seeing that. Very good point.
Patrick Karcher
I replaced inner join with left outer one, so that this query is equivalent to the original one.
AlexKuznetsov
In general, it is plain wrong that correlated subqueries work row by row. We can compare execution plans and see for ourselves.
AlexKuznetsov
Alex a direct quote from books online:"In queries that include a correlated subquery (also known as a repeating subquery), the subquery depends on the outer query for its values. This means that the subquery is executed repeatedly, once for each row that might be selected by the outer query."
HLGEM
@HLGEM and @AlexKuznetsov, I still don't think this will work unless table1 is enumerable. table1 would require an n column on which to join.
hypoxide
HLGEM, the quote from books online is just plain wrong. I'll bust that myth on sqlblog.com in a few minutes.
AlexKuznetsov
+2  A: 

most likely there will be no differenfce one way or another. I would run this:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

followed by both variants of your query, so that you see and compare real execution costs.

AlexKuznetsov
Thanks for this handy tip
hypoxide
+3  A: 

Keeping data in the datetime format using DATEADD is most likely to be quicker

Check this question: Most efficient way in SQL Server to get date from date+time?

The accepted answer (not me!) demonstrates DATEADD over string conversions. I've seen another too many years ago that showed the same

gbn
That's exactly the type of answer I was hoping for. +1 to you for finding it and +1 to Tomas for the great benchmark. Thanks!
hypoxide