План запроса CTE для сложного запроса - тройной запуск одного и того же запроса инициализации - почему? - PullRequest
1 голос
/ 02 октября 2010

Сложно объяснить, но я попробую. query plan pic

Как вы видите на прикрепленном изображении query_plan (это план запроса для "Все в одном месте" запроса, описанного ниже), есть 3 почти одинаковых "блока" - мой вопрос ПОЧЕМУ? Мне кажется, что когда у меня есть запрос «все в одном» (см. Ниже), блок «Init» (который довольно тяжелый) запускается три раза с разными фильтрами вместо того, чтобы быть SPOOLED и повторно использоваться позже.

Время выполнения этого запроса составляет около 45 секунд. Это запрос может быть представлен в виде:

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

Здесь важно то, что я последовательно использую эти таблицы Step1, Step2, ..., StepN в предложении WITH. Шаг 1 использует таблицу INIT, поэтому Step2 использует таблицу Step1, Step3 использует таблицу Step2 и т. Д. Мне это нужно из-за разного ранжирования я обрабатываю после каждого шага, который позже используется для фильтрации.

Если изменить этот сложный запрос CTE на (я положил результат запроса Init в таблицу, затем обработаю другие шаги без изменений):

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

У меня около 15 сек. Времени исполнения, что мне кажется нормальным. Потому что 10сек - это первый сложный запрос, который сложно улучшить.

Так в результате я не могу получить это поведение MS Sql server 2005? Может ли кто-нибудь объяснить это мне? Полагаю, это довольно интересно!

1 Ответ

1 голос
/ 02 октября 2010

Похоже, оптимизатор считает, что было бы быстрее выполнить запрос трижды при различных условиях. Оптимизатор не всегда прав.

На самом деле довольно часто используют временную таблицу, чтобы заставить SQL Server сначала выполнить весь сложный запрос. Обычно вы используете временную таблицу вместо test_init:

insert into #temptbl select * from Init

Временная таблица также используется SQL Server для хранения результатов объединений и подзапросов. Использование временной таблицы не оказывает негативного влияния на производительность.

...