2012-04-13 3 views
2

Ich habe eine gespeicherte Prozedur, wo ich einen gemeinsamen Tabellenausdruck verwende, um einen hierarchischen Pfad in einem Menü zu erstellen (so etwas wie Elternmenü -> Untermenü -> Sub-Untermenü -> ...)Beitritt zur CTE-Leistung

Es funktioniert gut für das, wofür ich es verwenden möchte, das Problem kommt, wenn ich die Informationen, die ich aus dem rekursiven CTE bekomme, in die Informationen setze, die ich wirklich will. Ich mache eine innere Verbindung von meinen Daten zum CTE und hole den hierarchischen Pfad heraus. Für etwas, das ~ 300 Zeilen zurückgibt, dauert die gespeicherte Prozedur durchschnittlich 15-20 Sekunden.

Wenn ich die Ergebnisse aus dem CTE in eine Temp-Tabelle einfüge und den Join darauf aufbaue, dauert die Prozedur weniger als eine Sekunde.

Ich habe mich nur gefragt, warum es so lange dauert, nur mit dem CTE beizutreten, oder wenn ich CTE's in irgendeiner Weise missbrauche.

** bearbeiten ist die gespeicherte Prozedur im Wesentlichen

With Hierarchical_Path (Menu_ID, Parent_ID, Path) 

As 
(
Select 
    EM.Menu_Id, Parent_ID, 
      Convert(varchar(max), 
      EM.Description) as Path 
From 
    Menu EM 
Where 
--EM.Topic_No is null 
    EM.Parent_ID = 0 and EM.Disabled = 0 
Union All 
Select 
    EM.Menu_ID, 
      EM.Parent_ID, 
      Convert(Varchar(max),E.Path + ' -> ' + EM.Description) as Path 
From 
    Menu EM 
Inner Join 
    Hierarchical_Path E 
On 
    EM.Parent_ID = E.Menu_ID  
) 

SELECT distinct 
    EM.Description 
    ,EMS.Path 
FROM 
    dbo.Menu em 
INNER JOIN 
    Hierarchical_Path EMS 
ON 
    EMS.Menu_ID = em.Menu_Id 
    2 more INNER JOINs 
    2 Left Joins 
    WHERE Clause 

Wenn ich die Abfrage wie folgt ausgeführt werden (auf den CTE Beitritt) ist die Leistung um 20 Sekunden.

Wenn ich die CTE-Ergebnisse in eine temporäre Tabelle einfüge und mich daran anschließe, ist die Leistung sofort.

Ich zerlege meine Anfrage ein bisschen mehr, es scheint, als ob sie auf der WHERE-Klausel aufgelegt wird. Ich denke, meine Frage ist mehr zu dem Punkt, wann genau ein CTE läuft und wird es im Speicher gespeichert? Ich lief unter der Annahme, dass es einmal aufgerufen wird und dann im Gedächtnis bleibt, aber unter bestimmten Umständen könnte es mehrere Male aufgerufen werden?

+3

Bitte zeigen Sie vergleichbare Fragen hier an. – Yuck

+0

Rekursive CTE sind relativ langsam und können mehrere Tabellen-Scans beinhalten. Sofern Sie keine näheren Angaben zu den CTE-Tabellen und der ungefähren Anzahl der Zeilen in diesen Tabellen machen, glaube ich, dass es unmöglich ist, Ihre Frage – a1ex07

+0

@ a1ex07 zu beantworten, was Sie überhaupt nicht sagen können. Ein nicht rekursiver CTE entspricht einer Ansicht. Es verschwindet vollständig während der Abfragekompilierung. Im rekursiven Fall kommt es ganz auf das an, was Sie tun. – usr

Antwort

1

Der Unterschied ist ein CTE ist nicht beibehalten und eine temporäre Tabelle ist (zumindest für die Sitzung). Das Verknüpfen mit einer nicht persistenten Spalte bedeutet, dass SQL für die Daten überhaupt keine Statistiken enthält, verglichen mit derselben Spalte in einer temporären Tabelle, die bereits vorab ausgewertet wurde. Im Grunde speichert die temporäre Tabelle, was Sie verwenden würden, und SQL Server kann sie besser optimieren. Die gleichen Probleme treten auf, wenn Sie das Ergebnis einer Funktion oder einer Tabellenvariablen verknüpfen.

Meine Vermutung ist, dass Ihr CTE-Ausführungsplan die Ausführung mit einem einzigen Thread ausführt, während Ihre temporäre Tabelle mehrere Threads verwenden kann. Sie können dies überprüfen, indem Sie beim Ausführen der Abfragen den tatsächlichen Ausführungsplan einbeziehen und nach zwei horizontalen Pfeilen suchen, die bei jedem Operator in entgegengesetzte Richtungen zeigen. Das deutet auf Parallelität hin.

P.S. - Versuchen Sie, "Statistiken setzen" und "Statistikzeit ein" einzustellen, um zu sehen, ob die tatsächlichen Kosten für die Ausführung der Abfragen unabhängig von der Ausführungsdauer gleich sind.