Потоковая рекурсивная CTE SQL Server 2008 - PullRequest
2 голосов
/ 19 января 2012

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

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

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

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

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

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

Фрагмент CTE для каждой записи, который я использую. В этом примере TableA - это Member, а TableB - это MemberReplace. Я вырвал большую часть оператора 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

1 Ответ

1 голос
/ 06 февраля 2012

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

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

Тогда:

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

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

Обновление

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

Обновление 2

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

...