Почему CTE (рекурсивный) не распараллелен (MAXDOP = 8)? - PullRequest
4 голосов
/ 18 июля 2011

У нас довольно большая машина с памятью 100 ГБ и 8+ ядрами.Серверный MAXDOP = 8.

T_SEQ_FF rowcount = 61692209, size = 2991152 KB  

UPD 1: Таблица T_SEQ_FF имеет два индекса:

1) create index idx_1 on T_SEQ_FF (first_num)
2) create index idx_2 on T_SEQ_FF (second_num)

Таблица T_SEQ_FF имеет first_num,second_num pairs чисел, которые должны обеспечивать последовательность после cte:

;with first_entity as ( 
    select first_num from  T_SEQ_FF a  where not exists (select 1 from  T_SEQ_FF b  where a.first_num = b.second_num) 
) ,
cte as ( 
select a.first_num, a.second_num, a.first_num as first_key, 1 as sequence_count 
from  T_SEQ_FF a  inner join first_entity b on a.first_num = b.first_num 
union all 
select a.first_num, a.second_num, cte.first_key, cte.sequence_count + 1 
from  T_SEQ_FF a  
inner join cte on a.first_num = cte.second_num 
) 
select * 
from cte 
option (maxrecursion 0); 

Но когда я запускаю этот запрос - я вижу только план последовательного запроса без параллелизма.Если бы я удалил 2-ю часть CTE из запроса выше:

union all 
    select a.first_num, a.second_num, cte.first_key, cte.sequence_count + 1 
    from  T_SEQ_FF a  
    inner join cte on a.first_num = cte.second_num 

, то я мог бы видеть, что план запроса становится Распараллеленным с использованием Repartition и Gather Streams.

Итак, я могу подвести итог, что это из-за recurisve CTE SQL Server не использует параллелизм при обработке этого запроса.

Я считаю, что на такой большой машине с тоннами свободных ресурсов параллелизм должен помочь быстрее завершить запрос.

Пока он работает около 40-50 минут.

Не могли бы вы посоветовать, как использовать столько ресурсов, сколько мы можем, чтобы завершить запрос быстрее?

CTE - единственный вариант, потому что нам нужно заполнить последовательности из пар first_num - second_num, и эти последовательности могутбыть любой длины.

Ответы [ 3 ]

1 голос
/ 20 июля 2011

Я не уверен, что это приемлемый вариант, но мы уже исключили многие другие традиционные подходы: можно ли сделать явное распараллеливание, разделив набор first_entity на части, а затем выполнив этот запрос параллельно по коду, и наконец, объедините эти наборы данных.

Это гораздо сложнее, чем просто решение t-sql, и я не знаю, сработает ли это с вашими данными, здесь могут возникнуть проблемы как с распределением, так и с блокировкой данных.

1 голос
/ 18 июля 2011

Я бы попытался переписать CTE, чтобы удалить один из шагов, например:

;cte as ( 
select a.first_num, a.second_num, a.first_num as first_key, 1 as sequence_count 
from  T_SEQ_FF a  where not exists (select 1 from  T_SEQ_FF b  where a.first_num = b.second_num) 
union all 
select a.first_num, a.second_num, cte.first_key, cte.sequence_count + 1 
from  T_SEQ_FF a  
inner join cte on a.first_num = cte.second_num 
) 
select * 
from cte 
option (maxrecursion 0);

Если есть только один корневой элемент, было бы лучше передать его в запрос как переменную, чтобы значение могло бытьиспользуется оптимизатором запросов.

Еще одна попытка - изменить запрос, чтобы получить корневые элементы без подзапроса, т. е. значение second_num равно нулю или first_num = second_num.

0 голосов
/ 08 февраля 2012

Я наткнулся на похожую проблему, и после тщательного анализа ситуации, а также проблемы в Производительность UNION ALL в SQL Server 2005 мне кажется, что ссылка на cte в запросе UNION ALL отключается распараллеливание (скорее всего, это ошибка).

...