views:

25

answers:

2

It's difficult to explain, but I'll try. query plan pic

As you see on query_plan picture attached (It is query plan for "All in one place" query described below), there are 3 almost the same "blocks" - my question is WHY? It seems to me that when I have "all in one" (see below) query the "Init" block (that is rather heavy) is run three times with different filters instead of being SPOOLED and reused later.

This Query exec time is about 45secs. It query could be presented in a form:

-- Complex "All in One place" Query
WITH init as (
  Init1 complex query here  -- (10 sec to run) if executed alone
)
, step1 as ( select * from init .. joins... where ... etc ), 
step2 as ( select *, row_number() over(__condition__) as rn from step1 where _filter1_)
, step3 as ( select * from step2 where __filter2_), 
.... some more steps could be here ....
select * 
into target_table
from step_N;
-- 45sec CPU time 

The important thing here is that I use those Step1, Step2, ..., StepN tables within "WITH" clause sequentially - Step 1 uses INIT table, so Step2 uses Step1 table, Step3 uses Step2 Table etc. I need this because of different rankings I process after every step that is used later for filtering.

If change this complex CTE query to (I put the result of Init query into table, then process other Steps without change):

-- Complex query separated from the rest of the query
 with Init as ( 
   The same Init1 complex query here
) 
select * 
into test_init 
from init;
-- 10sec CPU time

with step1 as ( select * from test_init .. joins... where ... etc ), 
step2 as ( select *, row_number() over(__condition__) as rn from step1 where _filter1_)  , 
step3 as ( select * from step2 where __filter2_), 
.... some more steps could be here ....
select * 
into target_table
from step_N; 
-- 5sec CPU time

I got about 15secs of exec time, that seems OK to me. Because 10sec is the 1st complex query that is difficult to improve.

So as a result I cant get this MS Sql server 2005 behavior? Could somebody explain this to me? It's rather interesting, I suppose!

+1  A: 

Looks like the optimizer thinks it would be faster to run the query thrice with different conditions. The optimizer is not always right.

It's actually pretty common to use a temporary table to force SQL Server to do the whole complex query first. Usually, you'd use a temporary table instead of test_init:

insert into #temptbl select * from Init

A temporary table is also used by SQL Server to store the results of joins and subqueries. Using a temporary table does not negatively impact performance.

Andomar
We use tables sometimes for QA purposes later. Temp Tables is used where appropriate. Hmmm... Is there a way to "tell" MS SQL that it's better to put the result in spool and reuse? Write a Plan, Hints, something?
zmische
@zmische - It might well be possible with plan hints but remember the spool will just be a work table in tempdb anyway.
Martin Smith
Yeah, You are right. But I'm about doing the work in one query, without additional select .. into from. Even more if it's the same from MS SQL server point of View. %) Thx anyway!
zmische
A: 

SQL Server generally doesn't materialize the result of Common Table Expressions.

It is possible to get it to spool the results though with some messing about (Article by Stack Overflow User Quassnoi).

There is a proposal on the Microsoft Connect site to make the NOEXPAND hint usable with CTEs to force this behaviour.

Martin Smith
NOEXPAND don't work on MSQ SQL 2005. OPTION (NOEXPAND) either. From mS connect article. Thx for mentioning Quassnoi's articles - they are brilliant!
zmische
@zmische - It doesn't work on any SQL Server Version - Vote for it if you want it! Agreed on the articles.
Martin Smith
Sorry, my mistake. I'll vote!
zmische
@zmische, @Martin Smith: It's currently be WITH (NOEXPAND) because it's a table hint...
gbn
@gbn: I tried with (noexpand) for queries in every step - the plan still the same. Perhaps Table hints are not taken into account by Optimizer for this case.
zmische
@zmische: that is correct. A CTE is a macro: there is no magic caching.
gbn