Оптимизация CTE для рекурсивных запросов - PullRequest
6 голосов
/ 22 апреля 2011

У меня есть таблица с самостоятельным соединением. Вы можете думать о структуре как о стандартной таблице для представления организационной иерархии. Например, таблица: -

MemberId
MemberName
RelatedMemberId

Эта таблица состоит из 50000 образцов записей. Я написал рекурсивный запрос CTE, и он работает абсолютно нормально. Однако время, необходимое для обработки всего 50000 записей, составляет около 3 минут на моей машине (4 ГБ оперативной памяти, 2,4 ГГц Core2Duo, 7200 об / мин HDD).

Как я могу улучшить производительность, потому что 50000 не так уж и много. Со временем оно будет расти. Это именно тот запрос, который у меня есть в моей хранимой процедуре. Цель запроса состоит в том, чтобы выбрать все элементы, относящиеся к определенному элементу. Например. Под владельцем компании приходит каждый человек. Для менеджера, кроме владельца, все записи возвращаются. Надеюсь, вы понимаете цель запроса.

SET ANSI_NULLS ON ИДТИ SET QUOTED_IDENTIFIER ON GO

Alter PROCEDURE spGetNonVirtualizedData
(
    @MemberId    int
)
AS
BEGIN

    With MembersCTE As
    (
        Select parent.MemberId As MemberId, 0 as Level
            From Members as parent Where IsNull(MemberId,0) = IsNull(@MemberId,0)

                    Union ALL
        Select    child.MemberId As MemberId , Level + 1 as Level
            From Members  as child
                Inner Join MembersCTE on MembersCTE.MemberId = child.RelatedMemberId
    )   
    Select Members.*
        From MembersCTE
        Inner Join Members On MembersCTE.MemberId = Members.MemberId
        option(maxrecursion 0)

END
GO

Как вы можете видеть, чтобы улучшить производительность, я даже сделал Объединения на последнем шаге, выбирая записи, чтобы все ненужные записи не вставлялись во временную таблицу. Если я сделал соединения на базовом и рекурсивном шагах CTE (вместо выбора на последнем шаге), выполнение запроса занимает 20 минут!

MemberId является первичным ключом в таблице.

Заранее спасибо:)

1 Ответ

9 голосов
/ 22 апреля 2011

В вашем состоянии привязки у вас есть Where IsNull(MemberId,0) = IsNull(@MemberId,0) Я предполагаю, что это просто потому, что когда вы передаете NULL в качестве параметра = не работает с точки зрения возврата IS NULL значений.Это приведет к сканированию, а не к поиску.

Используйте WHERE MemberId = @MemberId OR (@MemberId IS NULL AND MemberId IS NULL) вместо которого может быть sargable.

Также я предполагаю, что у вас не может быть индекса на RelatedMemberId.Если нет, то вам следует добавить один

CREATE NONCLUSTERED INDEX ix_name ON Members(RelatedMemberId) INCLUDE (MemberId)

(хотя вы можете пропустить бит включенного столбца, если MemberId является ключом кластеризованного индекса, поскольку он будет включен автоматически)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...