Behandeln von problemen mit langsamen Abfragen, die von dem Timeout des Abfrageoptimierrs betroffen sind
Gilt für: SQL Server
In diesem Artikel wird das Optimierertimeout vorgestellt, wie sich dies auf die Abfrageleistung auswirken kann und wie Sie die Leistung optimieren.
Was ist Optimierertimeout?
SQL Server verwendet einen kostenbasierten Abfrageoptimierer (QO). Informationen zu QO finden Sie im Leitfaden zur Abfrageverarbeitungsarchitektur. Ein kostenbasierter Abfrageoptimierer wählt einen Abfrageausführungsplan mit den niedrigsten Kosten aus, nachdem er mehrere Abfragepläne erstellt und bewertet hat. Eines der Ziele von SQL Server Query Optimizer ist es, im Vergleich zur Abfrageausführung eine angemessene Zeit in der Abfrageoptimierung zu verbringen. Das Optimieren einer Abfrage sollte viel schneller sein als die Ausführung. Um dieses Ziel zu erreichen, verfügt QO über einen integrierten Schwellenwert von Aufgaben, die berücksichtigt werden müssen, bevor er den Optimierungsprozess beendet. Wenn der Schwellenwert erreicht wird, bevor QO alle möglichen Pläne berücksichtigt hat, erreicht er das Optimierertimeoutlimit. Ein Optimierertimeout-Ereignis wird im Abfrageplan als TimeOut unter "Grund für vorzeitige Beendigung der Optimierung der Anweisung" gemeldet. Es ist wichtig zu verstehen, dass dieser Schwellenwert nicht auf der Uhrzeit basiert, sondern auf der Anzahl der vom Optimierer berücksichtigten Möglichkeiten. In aktuellen SQL Server-QO-Versionen werden über eine halbe Million Aufgaben berücksichtigt, bevor ein Timeout erreicht wird.
Das Timeout des Optimierers ist in SQL Server konzipiert, und in vielen Fällen ist es kein Faktor, der die Abfrageleistung beeinflusst. In einigen Fällen kann die Auswahl des SQL-Abfrageplans jedoch negativ von dem Optimierertimeout beeinflusst werden, und eine langsamere Abfrageleistung kann dazu führen. Wenn Sie solche Probleme feststellen, können Sie den Timeoutmechanismus des Optimierers verstehen und feststellen, wie komplexe Abfragen betroffen sind, Ihnen bei der Problembehandlung und Verbesserung der Abfragegeschwindigkeit helfen.
Das Ergebnis des Erreichens des Optimierer-Timeoutschwellenwerts ist, dass SQL Server nicht die gesamte Reihe von Optimierungsmöglichkeiten berücksichtigt hat. Das heißt, es gibt möglicherweise verpasste Pläne, die kürzere Ausführungszeiten erzeugen könnten. QO beendet den Schwellenwert und berücksichtigt zu diesem Zeitpunkt den Plan für die am wenigsten kostenintensive Abfrage, auch wenn es bessere, unerforschte Optionen geben kann. Beachten Sie, dass der nach erreichen eines Optimierertimeouts ausgewählte Plan eine angemessene Ausführungsdauer für die Abfrage erzeugen kann. In einigen Fällen kann der ausgewählte Plan jedoch zu einer Abfrageausführung führen, die suboptimal ist.
Wie erkennen Sie ein Optimierertimeout?
Dies sind Symptome, die auf ein Optimierertimeout hinweisen:
Komplexe Abfrage
Sie haben eine komplexe Abfrage, die viele verknüpfte Tabellen umfasst (z. B. acht oder mehr Tabellen werden verknüpft).
Langsame Abfrage
Die Abfrage kann langsam oder langsamer ausgeführt werden, als sie auf einer anderen SQL Server-Version oder einem anderen System ausgeführt wird.
Abfrageplan zeigt StatementOptmEarlyAbortReason=Timeout
Der Abfrageplan wird im XML-Abfrageplan angezeigt
StatementOptmEarlyAbortReason="TimeOut"
.<?xml version="1.0" encoding="utf-16"?> <ShowPlanXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Version="1.518" Build="13.0.5201.2" xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan"> <BatchSequence> <Batch> <Statements> <StmtSimple ..." StatementOptmLevel="FULL" StatementOptmEarlyAbortReason="TimeOut" ......> ... <Statements> <Batch> <BatchSequence>
Überprüfen Sie die Eigenschaften des Am häufigsten verwendeten Planoperators in Microsoft SQL Server Management Studio. Sie können den Wert von Reason For Early Termination of Statement Optimization sehen, ist TimeOut.
Was bewirkt ein Optimierertimeout?
Es gibt keine einfache Möglichkeit, zu bestimmen, welche Bedingungen dazu führen würden, dass der Optimiererschwellenwert erreicht oder überschritten wird. Die folgenden Abschnitte sind einige Faktoren, die beeinflussen, wie viele Pläne von QO untersucht werden, wenn Sie nach dem besten Plan suchen.
In welcher Reihenfolge sollten Tabellen verknüpft werden?
Hier ist ein Beispiel für die Ausführungsoptionen von Drei-Tabellen-Verknüpfungen (
Table1
,Table2
,Table3
):Table2
MitTable1
und dem Ergebnis mitTable3
Table3
MitTable1
und dem Ergebnis mitTable2
Table3
MitTable2
und dem Ergebnis mitTable1
Hinweis: Je größer die Anzahl von Tabellen ist, desto größer sind die Möglichkeiten.
Welche Heap- oder Binärstruktur (HoBT) access structure to retrieve the rows from a table?
- Gruppierter Index
- Nicht gruppierter Index1
- Nicht gruppierter Index2
- Tabellenhap
Welche physische Zugriffsmethode soll verwendet werden?
- Indexsuche
- Indexscan
- Tabellenscan
Welcher physische Verknüpfungsoperator soll verwendet werden?
- Verknüpfung geschachtelter Schleifen (NJ)
- Hashbeitritt (HJ)
- Zusammenführen der Verknüpfung (MJ)
- Adaptive Verknüpfung (beginnend mit SQL Server 2017 (14.x))
Weitere Informationen finden Sie im Artikel Joins (SQL Server).
Teile der Abfrage parallel oder seriell ausführen?
Weitere Informationen finden Sie unter Parallele Abfrageverarbeitung.
Die folgenden Faktoren verringern zwar die Anzahl der berücksichtigten Zugangsmethoden und somit die berücksichtigten Möglichkeiten:
- Abfrage-Prädikate (Filter in der
WHERE
Klausel) - Existenzen von Einschränkungen
- Kombinationen aus gut gestalteten und aktuellen Statistiken
Hinweis: Die Tatsache, dass QO den Schwellenwert erreicht, bedeutet nicht, dass es mit einer langsameren Abfrage endet. In den meisten Fällen wird die Abfrage gut ausgeführt, aber in einigen Fällen wird möglicherweise eine langsamere Abfrageausführung angezeigt.
Beispiel für die Berücksichtigung der Faktoren
Zur Veranschaulichung sehen wir ein Beispiel für eine Verknüpfung zwischen drei Tabellen (t1
, t2
und t3
) und jede Tabelle hat einen gruppierten Index und einen nicht gruppierten Index.
Berücksichtigen Sie zunächst die physischen Verknüpfungstypen. Hier sind zwei Verknüpfungen beteiligt. Und da es drei physische Verknüpfungsmöglichkeiten (NJ, HJ und MJ) gibt, kann die Abfrage auf 32 = 9 Arten ausgeführt werden.
- NJ - NJ
- NJ - HJ
- NJ - MJ
- HJ - NJ
- HJ - HJ
- HJ - MJ
- MJ - NJ
- MJ - HJ
- MJ - MJ
Betrachten Sie dann die Verknüpfungsreihenfolge, die mit Permutationen berechnet wird: P (n, r). Die Reihenfolge der ersten beiden Tabellen spielt keine Rolle, sodass es P(3,1) = 3 Möglichkeiten geben kann:
- Teilnehmen
t1
mitt2
und dann mitt3
- Teilnehmen
t1
mitt3
und dann mitt2
- Teilnehmen
t2
mitt3
und dann mitt1
Betrachten Sie als Nächstes die gruppierten und nicht gruppierten Indizes, die zum Abrufen von Daten verwendet werden können. Außerdem verfügen wir für jeden Index über zwei Zugriffsmethoden, Such- oder Überprüfungsmethoden. Das bedeutet, dass für jede Tabelle 2 2 = 4 Auswahlmöglichkeiten vorhanden sind. Wir haben drei Tabellen, sodass es 43 = 64 Auswahlmöglichkeiten gibt.
Unter Berücksichtigung all dieser Bedingungen kann es 9*3*64 = 1728 mögliche Pläne geben.
Angenommen, es gibt n Tabellen, die in der Abfrage verknüpft sind, und jede Tabelle verfügt über einen gruppierten Index und einen nicht gruppierten Index. Berücksichtigen Sie die folgenden Faktoren:
- Beitrittsaufträge: P(n,n-2) = n!/2
- Verknüpfungstypen: 3n-1
- Verschiedene Indextypen mit Such- und Scanmethoden: 4n
Multiplizieren Sie alle oben genannten, und wir können die Anzahl der möglichen Pläne erhalten: 2*n!*12n-1. Bei n = 4 beträgt die Zahl 82.944. Bei n = 6 beträgt die Zahl 358.318.080. Mit dem Anstieg der Anzahl der Tabellen, die an einer Abfrage beteiligt sind, erhöht sich die Anzahl möglicher Pläne also geometrisch. Wenn Sie die Möglichkeit von Parallelität und anderen Faktoren einbeziehen, können Sie sich vorstellen, wie viele mögliche Pläne berücksichtigt werden. Daher ist eine Abfrage mit vielen Verknüpfungen wahrscheinlicher, dass der Optimierer-Timeoutschwellenwert erreicht wird, als eine mit weniger Verknüpfungen.
Beachten Sie, dass die obigen Berechnungen das Szenario im ungünstigsten Fall veranschaulichen. Wie wir bereits erwähnt haben, gibt es Faktoren, die die Anzahl der Möglichkeiten verringern, wie Filter-Prädikate, Statistiken und Einschränkungen. Beispielsweise verringert ein Filter-Prädikat und aktualisierte Statistiken die Anzahl der physischen Zugriffsmethoden, da es effizienter sein kann, eine Indexsuche als eine Überprüfung zu verwenden. Dies führt auch zu einer kleineren Auswahl von Verknüpfungen usw.
Warum wird ein Optimierertimeout mit einer einfachen Abfrage angezeigt?
Nichts mit dem Abfrageoptimierer ist einfach. Es gibt viele mögliche Szenarien, und der Grad der Komplexität ist so hoch, dass es schwer ist, alle Möglichkeiten zu erfassen. Der Abfrageoptimierer kann den Timeoutschwellenwert basierend auf den Kosten des Plans, der in einer bestimmten Phase gefunden wurde, dynamisch festlegen. Wenn beispielsweise ein Plan gefunden wird, der relativ effizient erscheint, kann die Vorgangsgrenze für die Suche nach einem besseren Plan reduziert werden. Daher kann es sich bei der unterschätzten Kardinalitätsschätzung (CE) um ein Szenario handeln, bei dem ein Optimierertimeout frühzeitig getroffen wird. In diesem Fall liegt der Schwerpunkt der Untersuchung auf CE. Es ist ein seltenerer Fall im Vergleich zum Szenario zum Ausführen einer komplexen Abfrage, die im vorherigen Abschnitt erläutert wird, aber es ist möglich.
Auflösungen
Ein Optimierertimeout, das in einem Abfrageplan angezeigt wird, bedeutet nicht unbedingt, dass es die Ursache für die schlechte Abfrageleistung ist. In den meisten Fällen müssen Sie möglicherweise nichts über diese Situation tun. Der Abfrageplan, mit dem SQL Server endet, kann sinnvoll sein, und die abfrage, die Sie ausführen, ist möglicherweise gut geeignet. Möglicherweise wissen Sie nie, dass Sie ein Optimierertimeout gefunden haben.
Probieren Sie die folgenden Schritte aus, wenn Sie feststellen, dass Sie die Optimierung und Optimierung benötigen.
Schritt 1: Einrichten eines Basisplans
Überprüfen Sie, ob Sie dieselbe Abfrage mit demselben Dataset auf einem anderen Build von SQL Server ausführen können, indem Sie eine andere CE-Konfiguration oder ein anderes System (Hardwarespezifikationen) verwenden. Ein Leitprinzip bei der Leistungsoptimierung ist "es gibt kein Leistungsproblem ohne Basisplan". Daher wäre es wichtig, einen Basisplan für dieselbe Abfrage einzurichten.
Schritt 2: Suchen Sie nach "ausgeblendeten" Bedingungen, die zum Optimierertimeout führen
Untersuchen Sie Ihre Abfrage im Detail, um die Komplexität zu bestimmen. Bei der erstuntersuchung ist es möglicherweise nicht offensichtlich, dass die Abfrage komplex ist und viele Verknüpfungen umfasst. Ein häufiges Szenario ist, dass Ansichten oder Tabellenwertfunktionen beteiligt sind. Beispielsweise kann die Abfrage auf der Oberfläche einfach erscheinen, da sie zwei Ansichten verknüpft. Wenn Sie jedoch die Abfragen in den Ansichten untersuchen, stellen Sie möglicherweise fest, dass jede Ansicht sieben Tabellen verknüpft. Wenn die beiden Ansichten verknüpft sind, erhalten Sie daher eine 14-Tabellenverknnung. Wenn Ihre Abfrage die folgenden Objekte verwendet, führen Sie einen Drilldown zu den einzelnen Objekten durch, um zu sehen, wie die zugrunde liegenden Abfragen darin aussehen:
- Ansichten
- Tabellenwertfunktionen (TFVs)
- Unterabfragen oder abgeleitete Tabellen
- Allgemeine Tabellenausdrücke (CTEs)
- UNION-Operatoren
In all diesen Szenarien würde die am häufigsten verwendete Lösung darin bestehen, die Abfrage umzuschreiben und in mehrere Abfragen aufzuteilen. Weitere Details finden Sie in Schritt 7: Verfeinern der Abfrage .
Unterabfragen oder abgeleitete Tabellen
Die folgende Abfrage ist ein Beispiel, das zwei separate Sätze von Abfragen (abgeleitete Tabellen) mit jeweils 4 bis 5 Verknüpfungen verknüpft. Nach der Analyse durch SQL Server wird sie jedoch in einer einzigen Abfrage mit acht verknüpften Tabellen kompiliert.
SELECT ...
FROM
( SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
WHERE ...
) AS derived_table1
INNER JOIN
( SELECT ...
FROM t5
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...
WHERE ...
) AS derived_table2
ON derived_table1.Co1 = derived_table2.Co10
AND derived_table1.Co2 = derived_table2.Co20
Allgemeine Tabellenausdrücke
Die Verwendung mehrerer gängiger Tabellenausdrücke (CTEs) ist keine geeignete Lösung, um eine Abfrage zu vereinfachen und Optimierertimeout zu vermeiden. Mehrere CTEs erhöhen nur die Komplexität der Abfrage. Daher ist es kontraproduktiv, CTEs beim Lösen von Optimierertimeouts zu verwenden. CTEs sehen so aus, dass eine Abfrage logisch umgebrochen wird, aber sie werden in einer einzigen Abfrage kombiniert und als einzelne große Verknüpfung von Tabellen optimiert.
Hier ist ein Beispiel für eine CTE, die als einzelne Abfrage mit vielen Verknüpfungen kompiliert wird. Es kann vorkommen, dass die Abfrage für die my_cte eine einfache Verknüpfung mit zwei Objekten ist, aber tatsächlich gibt es sieben weitere Tabellen, die in der CTE verknüpft sind.
WITH my_cte AS (
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
JOIN t5 ON ...
JOIN t6 ON ...
JOIN t7 ON ...
WHERE ... )
SELECT ...
FROM my_cte
JOIN t8 ON ...
Ansichten
Stellen Sie sicher, dass Sie die Ansichtsdefinitionen überprüft und alle tabellen einbezogen haben. Ähnlich wie CTEs und abgeleitete Tabellen können Verknüpfungen in Ansichten ausgeblendet werden. Beispielsweise kann es sich bei einer Verknüpfung zwischen zwei Ansichten letztlich um eine einzelne Abfrage mit acht beteiligten Tabellen handeln:
CREATE VIEW V1 AS
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
WHERE ...
GO
CREATE VIEW V2 AS
SELECT ...
FROM t5
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...
WHERE ...
GO
SELECT ...
FROM V1
JOIN V2 ON ...
Tabellenwertfunktionen (TVFs)
Einige Verknüpfungen sind möglicherweise in TFVs ausgeblendet. Das folgende Beispiel zeigt, was als Verknüpfung zwischen zwei TFVs angezeigt wird, und eine Tabelle kann eine Neun-Tabellen-Verknüpfung sein.
CREATE FUNCTION tvf1() RETURNS TABLE
AS RETURN
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
WHERE ...
GO
CREATE FUNCTION tvf2() RETURNS TABLE
AS RETURN
SELECT ...
FROM t5
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...
WHERE ...
GO
SELECT ...
FROM tvf1()
JOIN tvf2() ON ...
JOIN t9 ON ...
Union
Union-Operatoren kombinieren die Ergebnisse mehrerer Abfragen in einem einzigen Resultset. Sie kombinieren auch mehrere Abfragen in einer einzigen Abfrage. Dann erhalten Sie möglicherweise eine einzelne, komplexe Abfrage. Das folgende Beispiel endet mit einem einzelnen Abfrageplan, der 12 Tabellen umfasst.
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
UNION ALL
SELECT ...
FROM t5
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...
UNION ALL
SELECT ...
FROM t9
JOIN t10 ON ...
JOIN t11 ON ...
JOIN t12 ON ...
Schritt 3: Wenn Sie eine Basisplanabfrage haben, die schneller ausgeführt wird, verwenden Sie dessen Abfrageplan.
Wenn Sie feststellen, dass ein bestimmter Basisplan, den Sie von Schritt 1 erhalten, besser für Ihre Abfrage durch Tests geeignet ist, verwenden Sie eine der folgenden Optionen, um QO zum Auswählen dieses Plans zu erzwingen:
- gespeicherte Prozedur für Abfragespeicher (QDS)
- Abfragehinweis: OPTION (USE PLAN N'XML_Plan<>')
- Planhinweislisten
Schritt 4: Reduzieren der Optionen für Pläne
Um die Wahrscheinlichkeit eines Optimierertimeouts zu verringern, versuchen Sie, die Möglichkeiten zu reduzieren, die QO bei der Auswahl eines Plans berücksichtigen muss. Dieser Vorgang umfasst das Testen der Abfrage mit unterschiedlichen Hinweisoptionen. Wie bei den meisten Entscheidungen mit QO sind die Auswahlmöglichkeiten nicht immer deterministisch auf der Oberfläche, da es eine Vielzahl von Faktoren gibt, die berücksichtigt werden müssen. Daher gibt es keine einzige garantierte erfolgreiche Strategie, und der ausgewählte Plan kann die Leistung der ausgewählten Abfrage verbessern oder verringern.
Erzwingen einer JOIN-Bestellung
Wird OPTION (FORCE ORDER)
verwendet, um die Reihenfolge permutation zu beseitigen:
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
OPTION (FORCE ORDER)
Reduzieren der JOIN-Möglichkeiten
Wenn andere Alternativen nicht geholfen haben, versuchen Sie, die Kombinationen des Abfrageplans zu reduzieren, indem Sie die Auswahl physischer Verknüpfungsoperatoren mit Verknüpfungshinweisen einschränken. Beispiel: OPTION (HASH JOIN, MERGE JOIN)
, OPTION (HASH JOIN, LOOP JOIN)
oder OPTION (MERGE JOIN)
.
Hinweis: Sie sollten beim Verwenden dieser Hinweise vorsichtig sein.
In einigen Fällen kann das Einschränken des Optimierrs mit weniger Verknüpfungsoptionen dazu führen, dass die beste Verknüpfungsoption nicht verfügbar ist und die Abfrage tatsächlich verlangsamt wird. Außerdem ist in einigen Fällen eine bestimmte Verknüpfung durch einen Optimierer erforderlich (z . B. Zeilenziel), und die Abfrage kann einen Plan nicht generieren, wenn diese Verknüpfung keine Option ist. Überprüfen Sie daher nach dem Ziel der Verknüpfungshinweise für eine bestimmte Abfrage, ob Sie eine Kombination finden, die eine bessere Leistung bietet, und beseitigt das Optimierertimeout.
Hier sind zwei Beispiele für die Verwendung solcher Hinweise:
Wird verwendet
OPTION (HASH JOIN, LOOP JOIN)
, um nur Hash- und Schleifenbeitritte zuzulassen und die Zusammenführungsbeiführung in der Abfrage zu vermeiden:SELECT ... FROM t1 JOIN t2 ON ... JOIN t3 ON ... JOIN t4 ON ... JOIN t5 ON ... OPTION (HASH JOIN, LOOP JOIN)
Erzwingen einer bestimmten Verknüpfung zwischen zwei Tabellen:
SELECT ... FROM t1 INNER MERGE JOIN t2 ON ... JOIN t3 ON ... JOIN t4 ON ... JOIN t5 ON ...
Schritt 5: Ändern der CE-Konfiguration
Versuchen Sie, die CE-Konfiguration zu ändern, indem Sie zwischen Legacy CE und New CE wechseln. Das Ändern der CE-Konfiguration kann dazu führen, dass QO einen anderen Pfad auswählt, wenn SQL Server Abfragepläne auswertet und erstellt. Selbst wenn ein Timeoutproblem des Optimierers auftritt, ist es möglich, dass Sie mit einem Plan enden, der mit der alternativen CE-Konfiguration optimal ausgeführt wird. Weitere Informationen finden Sie unter Aktivieren des besten Abfrageplans (Kardinalitätsschätzung).
Schritt 6: Aktivieren von Optimiererkorrekturen
Wenn Sie keine Korrekturen für den Abfrageoptimierer aktiviert haben, sollten Sie diese mithilfe einer der folgenden beiden Methoden aktivieren:
- Serverebene: Verwenden Sie das Ablaufverfolgungskennzeichnung T4199.
- Datenbankebene: Verwenden
ALTER DATABASE SCOPED CONFIGURATION ..QUERY_OPTIMIZER_HOTFIXES = ON
oder Ändern von Datenbankkompatibilitätsstufen für SQL Server 2016 und höhere Versionen.
Die QO-Korrekturen können dazu führen, dass der Optimierer einen anderen Weg bei der Planung der Erkundung nimmt. Daher kann er einen optimalen Abfrageplan auswählen. Weitere Informationen finden Sie unter SQL Server-Abfrageoptimierer-Hotfixablaufverfolgungskennzeichnung 4199-Wartungsmodell.
Schritt 7: Verfeinern der Abfrage
Erwägen Sie das Aufteilen der einzelnen Mehrtabellenabfrage in mehrere separate Abfragen mithilfe temporärer Tabellen. Das Aufteilen der Abfrage ist nur eine der Möglichkeiten, die Aufgabe für den Optimierer zu vereinfachen. Siehe folgendes Beispiel:
SELECT ...
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
JOIN t5 ON ...
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...
Um die Abfrage zu optimieren, versuchen Sie, die einzelne Abfrage in zwei Abfragen aufzuteilen, indem Sie einen Teil der Verknüpfungsergebnisse in eine temporäre Tabelle einfügen:
SELECT ...
INTO #temp1
FROM t1
JOIN t2 ON ...
JOIN t3 ON ...
JOIN t4 ON ...
GO
SELECT ...
FROM #temp1
JOIN t5 ON ...
JOIN t6 ON ...
JOIN t7 ON ...
JOIN t8 ON ...