Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Frage zur Deep-First-Leistung von SQL Server HierarchyID

Es ist nicht ganz klar, ob Sie versuchen, für die Tiefensuche oder die Breitensuche zu optimieren. Die Frage suggeriert Tiefe-zuerst, aber die Kommentare am Ende beziehen sich auf die Breite-zuerst.

Sie haben alle Indizes, die Sie für die Tiefensuche benötigen (indizieren Sie einfach die hierarchyid Säule). Für die Breite zuerst reicht es nicht aus, nur zu erstellen das berechnete level Spalte, müssen Sie diese ebenfalls indizieren:

ALTER TABLE Message
ADD [Level] AS MessageID.GetLevel()

CREATE INDEX IX_Message_BreadthFirst
ON Message (Level, MessageID)
INCLUDE (...)

(Beachten Sie, dass Sie für nicht geclusterte Indizes höchstwahrscheinlich den INCLUDE benötigen - Andernfalls kann SQL Server stattdessen auf einen Clustered-Index-Scan zurückgreifen.)

Nun, wenn Sie versuchen, alle Vorfahren zu finden eines Knotens möchten Sie einen etwas anderen Weg einschlagen. Sie können diese Suchen blitzschnell durchführen, denn - und hier ist das Coole an hierarchyid - jeder Knoten "enthält" bereits alle seine Vorfahren.

Ich verwende eine CLR-Funktion, um dies so schnell wie möglich zu machen, aber Sie können es mit einem rekursiven CTE tun:

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

Um nun alle Vorfahren und Nachkommen zu erhalten, verwenden Sie es wie folgt:

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

Probieren Sie es aus - dies sollte Ihre Leistungsprobleme lösen.