2010-04-26 11 views
8

Sto cercando di implementare gerarchyID in una tabella (dbo. [Message]) contenente circa 50.000 righe (crescerà sostanzialmente in futuro). Tuttavia ci vogliono 30-40 secondi per recuperare circa 25 risultati.Domanda su HierarchyID di SQL Server prestazioni di primo livello

Il nodo radice è un riempimento per fornire univocità, quindi ogni riga successiva è figlia di tale riga fittizia.

Devo essere in grado di attraversare la tabella depth-first e ho reso la colonna hierarchyID (dbo. [Message] .MessageID) la chiave primaria di clustering, ho anche aggiunto un piccoloint calcolato (dbo. [Message] .Hierarchy) che memorizza il livello del nodo.

Utilizzo: Un'applicazione .Net passa attraverso un valore di gerarchia ID nel database e voglio essere in grado di recuperare tutti i (eventuali) figli E genitori di quel nodo (oltre alla radice, poiché è riempitivo).

Una versione semplificata della query che sto usando:

@MessageID hierarchyID /* passed in from application */ 

SELECT 
m.MessageID, m.MessageComment 

FROM 
dbo.[Message] as m 

WHERE 
m.Messageid.IsDescendantOf(@MessageID.GetAncestor((@MessageID.GetLevel()-1))) = 1 

ORDER BY 
m.MessageID 

Da quello che ho capito, l'indice dovrebbe essere rilevato automaticamente senza un suggerimento.

Dalla ricerca di forum ho visto persone che utilizzano suggerimenti di indice quando si tratta di indici di larghezza, ma non hanno osservato questa applicazione in situazioni di profondità. Sarebbe un approccio rilevante per il mio scenario?

Ho passato gli ultimi giorni a cercare di trovare una soluzione per questo problema, ma senza risultato. Apprezzerei molto ogni tipo di assistenza, e poiché questo è il mio primo post, mi scuso in anticipo se questa sarebbe considerata una domanda "noobish", ho letto la documentazione MS e ho cercato innumerevoli forum, ma non ho trovato una descrizione sintetica del problema specifico.

+0

A proposito, la query che hai? Come scritto, va sempre selezionare TUTTI i nodi nell'intera tabella. Il '@ MessageID.GetAncestor (@ MessageID.GetLevel() - 1)' lo porta fino alla radice, e quindi si seleziona tutto ciò che è un discendente, che è ... tutto. Ecco perché è così lento. – Aaronaught

+0

Giusto per chiarire: la mia situazione richiede l'uso dell'indicizzazione approfondita, scusa per la confusione (mi riferivo all'estensione alla fine semplicemente per fornire un esempio di dove le persone hanno suggerito di usare i suggerimenti dell'indice) – ObjectiveCat

risposta

2

soluzione trovata qui: http://connect.microsoft.com/SQLServer/feedback/details/532406/performance-issue-with-hierarchyid-fun-isdescendantof-in-where-clause#

Basta ricordare che ho iniziato con un passato nel heirarchyID dall'applicazione e il mio obiettivo è quello di recuperare qualsiasi e tutti i parenti di quel valore (sia antenati e discendenti).

Nel mio caso specifico, ho dovuto aggiungere le seguenti dichiarazioni prima della SELECT dichiarazione:

declare @topNode hierarchyid = (select @messageID.GetAncestor((@messageID.GetLevel()-1))) 
declare @topNodeParent hierarchyid = (select @topNode.GetAncestor(1)) 
declare @leftNode hierarchyid= (select @topNodeParent.GetDescendant (null, @topNode)) 
declare @rightNode hierarchyid= (select @topNodeParent.GetDescendant (@topNode, null)) 

La clausola WHERE è stato cambiato in:

aumento delle prestazioni
messageid.IsDescendantOf(@topNode)=1 AND (messageid > @leftNode) AND (messageid < @rightNode) 

L'interrogazione è molto significativo :

Per ogni risultato passato, il tempo di ricerca è ora in media 20ms (era compreso tra 120 e 420).

Durante l'interrogazione di 25 valori, in precedenza erano necessari 25 - 35 secondi per restituire tutti i nodi correlati (in alcuni casi ogni valore aveva molti parenti, in alcuni non ce n'erano). Ora ci vogliono solo 2 secondi.

Grazie mille a tutti coloro che hanno contribuito a questo problema su questo sito e su altri.

8

Non è del tutto chiaro se si stia tentando di ottimizzare per la ricerca in profondità o in ampiezza; la domanda suggerisce un approfondimento, ma i commenti alla fine riguardano l'ampiezza.

Hai tutti gli indici necessari per la profondità (basta indicizzare la colonna hierarchyid). Per ampiezza, non è sufficiente solo per creare il level colonna calcolata, è necessario indicizzarlo troppo:

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

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

(Si noti che per gli indici non cluster che molto probabilmente bisogno della INCLUDE - altrimenti , SQL Server può ricorrere a fare una scansione indice cluster, invece.)

Ora, se si sta cercando di trovare tutte le antenati di un nodo, si vuole prendere una strada leggermente diversa. Puoi fare queste ricerche in modo fulmineo, perché - ed ecco cosa è bello su hierarchyid - ogni nodo già "contiene" tutti i suoi antenati.

Io uso una funzione CLR per rendere questo il più velocemente possibile, ma si può fare con una CTE ricorsiva:

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 

Ora, per ottenere tutti gli antenati e discendenti, usare in questo modo:

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 

Provalo - questo dovrebbe risolvere i vostri problemi di prestazioni.

+0

Ci scusiamo per confusione, profondità-prima è davvero quello che sto cercando! Grazie mille per il suggerimento, lo proverò subito. – ObjectiveCat

+0

Proprio per scopi di test, ho rimosso @ MessageID.GetAncestor tutto lasciando solo: m.MessageId.IsDescendantOf (@MessageID) = 1 nella clausola WHERE e quando mi sono imbattuto che proc, tempo di ricerca è ancora tra i 150 a 420 ms per risultato, che è molto lento per la mia applicazione. Le prestazioni sono una priorità e non ho familiarità con CLR, tuttavia mi piacerebbe davvero imparare come implementarlo, se ciò fornirebbe le migliori prestazioni. Qualche suggerimento da dove cominciare? – ObjectiveCat

+0

@AndalusianCat: la versione CLR è per la query antenato. Se lo trovi lento usando semplicemente 'IsDescendantOf', si prega di pubblicare una query reale, uno schema di tabella (inclusi gli indici) e il piano di esecuzione. Le query 'hierarchyid' sono in genere molto più veloci di così. – Aaronaught

Problemi correlati