2012-01-19 7 views
2

У меня есть набор данных из таблицы (TableA), которая относится к себе через TableB. Родители в TableA есть дети в TableA. У этих детей также могут быть дети. Ничего удивительного здесь.Streaming SQL Server 2008 Рекурсивные CTE

У меня есть набор строк верхнего уровня от TableA, над которым мне нужно работать. Прежде чем я смогу работать с этими строками, я должен иметь каждую дочернюю строку под рукой. Я должен иметь возможность работать в каждой строке верхнего уровня TableA (и это дети) как можно быстрее в моем приложении.

Я не могу найти способ сделать это.

Использование рекурсивного CTE (TableA набор верхнего уровня как анкер, TableB->TableA join as union), не соответствует требованиям. Весь набор верхнего уровня от TableA возвращается в CTE, прежде чем он будет работать на уровне 2 детей. Затем он работает на уровне 3. Затем уровень 4 и т. Д. Так как мой набор верхнего уровня составляет около 400 000 плюс строки, мое клиентское приложение не может начинать работу над строками до тех пор, пока на сервере не будет загружен набор данных ENTIRE.

Мне нужен лучший способ сделать это. Я попытался передать клиенту плоский набор строк верхнего уровня TableA, а клиент повторно выдал рекурсивный оператор CTE для каждой строки верхнего уровня TableA. Это действительно работает. Но слишком много шума. Постоянная скорость поиска строк слишком велика из-за повторной повторной выдачи инструкций.

Мне нужно творческое решение.

Фрагмент из-за записи CTE, которую я использую. В этом примере TableA является членом, а TableB является MemberReplacement. Я вырвал большую часть выражения select в середине и большую часть соединений.

WITH T_MemberRecurse 
(
    MemberId, 
    IncludedMemberId, 
    Level 
) AS (
    SELECT  Member.Id, 
       Member.Id, 
       0 
    FROM  MemberInput 
    INNER JOIN MemberInputItem 
     ON  MemberInputItem.MemberInputId = MemberInput.Id 
    INNER JOIN Member 
     ON  Member.Id = MemberInputItem.MemberId 
    UNION ALL 
    SELECT  T_MemberRecurse.MemberId, 
       Member2.Id, 
       Level + 1 
    FROM  T_MemberRecurse 
    INNER JOIN Member 
     ON  Member.Id = T_MemberRecurse.IncludedMemberId 
    INNER JOIN MemberReplacement 
     ON  MemberReplacement.MemberId = Member.Id 
    INNER JOIN Member Member2 
     ON  Member2.Id = MemberReplacement.OriginalMemberId 
) 
SELECT  Member.Id, 
      T_MemberRecurse.IncludedMemberId, 
      T_MemberRecurse.Level, 

FROM  MemberInput 
INNER JOIN LotsOfTables 
+0

Можете ли вы разместить образец кода и образцы данных? – JNK

+0

Просто сделал. Я добавил пример CTE для записи. Проблема с примерами проводки для этого заключается в том, что ни один из моих примеров даже не разработан для решения проблемы. – wasabi

+0

Извините, * «не спроектирован правильно» * - что вы подразумеваете под этим? Ваши текущие решения возвращают неверные результаты или они недостаточно эффективны? –

ответ

1

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

Включите CTE в функцию набора строк с одним параметром, желаемым идентификатором пользователя.

Тогда:

SELECT 
    * 
FROM 
    Member M 
    CROSS APPLY dbo.MemberChildren(M.Id) C 
WHERE 
    {Conditions for desired set of Members here} 
WITH (FAST 20); 

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

Update

Вторая идея: получить родительскую и детскую информацию отдельно и выполнять, по логике вещей, слияние присоединиться к клиенту. (Упорядоченный вложенный цикл, который только продвигает упорядоченный второй/внутренний вход, пока он не будет соответствовать.) Получите меньшие куски сразу, используя диапазоны ключей или row_number. Или получите весь родительский набор, затем получите меньший набор дочерних строк.

Update 2

Идея 3: Вместо рекурсивного CTE используйте 5 равнину ваниль соединяется, чтобы получить все необходимые данные. Это звучит ужасно, но вы должны сделать FAST 100, чтобы начать работу с данными.

+0

Хм. Это может сработать. Старался избегать объявления функции для ее выполнения, но это может быть уместно и может работать нормально. Я отдам его в понедельник. – wasabi

+0

CROSS APPLY с подзапросом, содержащим внешнюю ссылку, теоретически может идти глубоко, но, возможно, нет. Таким образом, функция. – ErikE

+0

Если бы вы могли поставить CTE в подзапрос, я бы решил это некоторое время назад. =/ – wasabi

Смежные вопросы