Не совсем ясно, пытаетесь ли вы оптимизировать поиск по глубине или по ширине; вопрос предполагает глубину, но комментарии в конце о ширине.
У вас есть все индексы, которые вам нужны для глубины (просто индексируйте столбец hierarchyid
). Во-первых, недостаточно просто создать вычисляемый столбец level
, вы также должны проиндексировать его:
ALTER TABLE Message
ADD [Level] AS MessageID.GetLevel()
CREATE INDEX IX_Message_BreadthFirst
ON Message (Level, MessageID)
INCLUDE (...)
(Обратите внимание, что для некластеризованных индексов вам, скорее всего, понадобится INCLUDE
- в противном случае SQL Server может вместо этого прибегнуть к сканированию кластерного индекса.)
Теперь, если вы пытаетесь найти всех предков узла, вы хотите пойти по-другому. Вы можете сделать этот поиск молниеносным, потому что - и вот что круто в hierarchyid
- каждый узел уже «содержит» всех своих предков.
Я использую функцию CLR, чтобы сделать это как можно быстрее, но вы можете сделать это с помощью рекурсивного CTE:
CREATE FUNCTION dbo.GetAncestors
(
@h hierarchyid
)
RETURNS TABLE
AS RETURN
WITH Hierarchy_CTE AS
(
SELECT @h AS id
UNION ALL
SELECT h.id.GetAncestor(1)
FROM Hierarchy_CTE h
WHERE h.id <> hierarchyid::GetRoot()
)
SELECT id FROM Hierarchy_CTE
Теперь, чтобы получить всех предков и потомков, используйте это так:
DECLARE @MessageID hierarchyID /* passed in from application */
SELECT m.MessageID, m.MessageComment
FROM Message as m
WHERE m.MessageId.IsDescendantOf(@MessageID) = 1
OR m.MessageId IN (SELECT id FROM dbo.GetAncestors(@MessageID.GetAncestor(1)))
ORDER BY m.MessageID
Попробуйте - это должно решить ваши проблемы с производительностью.