Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Question sur les performances en profondeur de SQL Server HierarchyID

Il n'est pas tout à fait clair si vous essayez d'optimiser la recherche en profondeur d'abord ou en largeur d'abord; la question suggère la profondeur d'abord, mais les commentaires à la fin concernent la largeur d'abord.

Vous avez tous les index dont vous avez besoin pour la profondeur d'abord (indexez simplement le hierarchyid colonne). Pour la largeur d'abord, il ne suffit pas de créer le level calculé colonne, vous devez également l'indexer :

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

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

(Notez que pour les index non clusterisés, vous aurez probablement besoin du INCLUDE - sinon, SQL Server peut avoir recours à une analyse d'index cluster à la place.)

Maintenant, si vous essayez de trouver tous les ancêtres d'un nœud, vous voulez prendre une approche légèrement différente. Vous pouvez rendre ces recherches ultra-rapides, car - et voici ce qui est cool avec hierarchyid - chaque nœud "contient" déjà tous ses ancêtres.

J'utilise une fonction CLR pour rendre cela aussi rapide que possible, mais vous pouvez le faire avec un CTE récursif :

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

Maintenant, pour obtenir tous les ancêtres et descendants, utilisez-le comme ceci :

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

Essayez-le - cela devrait résoudre vos problèmes de performances.