[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

bendlam

3/20/2007 8:01:00 PM

I recently re-wrote a simple sp that given a start and end date it
will spit out all the days that are not weekend days or holidays as
specified in a holiday table.

This function originally did a WHILE loop incrementing the days then
checking each individual day if it was a holiday or weekend, then
inserted it into a table variable, then increment the day and continue
looping.

i.e.
WHILE @day < @endDate
IF NotHoliday(@day)
INSERT INTO @tempTable
DATEADD(d, 1, @day)


I changed this to now return all days using a CTE and then doing a
DELETE to remove the holidays
WITH CTE(Day)
AS
(
SELECT @startDate
UNION ALL
SELECT DATEADD(d, 1, Day)
FROM CTE
WHERE Day < @endDate
)
INSERT INTO @tempTable
SELECT * FROM CTE

DELETE @tempTable
WHERE NotHoliday(Day) = False

So the CTE outperforms the old method considerbly but the BIG QUESTION
is WHY?

Is it because the recursive nature of CTE's are done in memory? What
is the main difference when using CTE's over Loops that make it that
much more efficient? It seems from the profiler it the CTE does more
reads but the duration is much longer. I know reads are a better
indication of query performance but the difference in duration is too
dramatic to ignore. Can somebody explain in such scenarios where a
rewrite of an sp to use recursive CTE's would perform better than a
traditional looping method?

Thank you

2 Answers

Aaron [SQL Server MVP]

3/20/2007 8:06:00 PM

0

It's the lack of a loop. In the old method, you are increasing the day by
1, performing an operation, increasing the day by 1, performing an
operation, increasing the day by 1, performing an operation... with the CTE,
you are performing two set-based operations *total* (set-based operations
are where SQL Server excels). The more days in your range, the more
pronounced the difference will be.

--
Aaron Bertrand
SQL Server MVP
http://www.sq...
http://www.aspfa...





"blam" <bendlam@gmail.com> wrote in message
news:1174420843.050378.319650@e65g2000hsc.googlegroups.com...
>I recently re-wrote a simple sp that given a start and end date it
> will spit out all the days that are not weekend days or holidays as
> specified in a holiday table.
>
> This function originally did a WHILE loop incrementing the days then
> checking each individual day if it was a holiday or weekend, then
> inserted it into a table variable, then increment the day and continue
> looping.
>
> i.e.
> WHILE @day < @endDate
> IF NotHoliday(@day)
> INSERT INTO @tempTable
> DATEADD(d, 1, @day)
>
>
> I changed this to now return all days using a CTE and then doing a
> DELETE to remove the holidays
> WITH CTE(Day)
> AS
> (
> SELECT @startDate
> UNION ALL
> SELECT DATEADD(d, 1, Day)
> FROM CTE
> WHERE Day < @endDate
> )
> INSERT INTO @tempTable
> SELECT * FROM CTE
>
> DELETE @tempTable
> WHERE NotHoliday(Day) = False
>
> So the CTE outperforms the old method considerbly but the BIG QUESTION
> is WHY?
>
> Is it because the recursive nature of CTE's are done in memory? What
> is the main difference when using CTE's over Loops that make it that
> much more efficient? It seems from the profiler it the CTE does more
> reads but the duration is much longer. I know reads are a better
> indication of query performance but the difference in duration is too
> dramatic to ignore. Can somebody explain in such scenarios where a
> rewrite of an sp to use recursive CTE's would perform better than a
> traditional looping method?
>
> Thank you
>


Hugo Kornelis

3/20/2007 11:47:00 PM

0

On 20 Mar 2007 13:00:43 -0700, blam wrote:

>So the CTE outperforms the old method considerbly but the BIG QUESTION
>is WHY?
(snip)

Hi blam,

Aaron answered this already. I just wanted to add that you can increase
the performance even further by including the selection for holidays in
the first query:

WITH CTE(Day)
AS
(
SELECT @startDate
UNION ALL
SELECT DATEADD(d, 1, Day)
FROM CTE
WHERE Day < @endDate
)
INSERT INTO @tempTable
SELECT * FROM CTE
WHERE NotHoliday(Day) <> False;

BTW: SQL Server has no boolean types, so the "False" above should result
in an error. I copied it from your message, but I guess that your real
code looks different.

BTW 2: another performance improvement MIGHT be possible by merging the
code from the NotHoliday function (which, incidentally, should be
prefixed by the owner - another error I copied from your message) inside
the query.

--
Hugo Kornelis, SQL Server MVP
My SQL Server blog: http://sqlblog.com/blogs/hug...