2015-08-07 9 views
5

Ich habe ein Leistungsproblem.Multiples INNER JOIN ist zu langsam SQL SERVER

Ich habe eine Tabelle erstellt, die Daten aus einer Datei empfängt, ich mache eine BULK INSERT. Dann mache ich einen SELECT mit mehreren INNER JOIN s (11 innere Joins), um in eine andere Tabelle mit den richtigen Daten einzufügen.

Wenn ich diese SELECT ausführen, dauert es zu lange (mehr als eine Stunde) und dann höre ich auf. Meine Lösung bestand darin, diese Abfrage in 3 zu unterteilen und @temp Tabellen zu erstellen. Zu meiner Überraschung dauert das 3 Minuten. Das ist, was ich versuche zu verstehen, warum brechen meine Abfrage in 3 war schneller als eine Select-Anweisung. Hier ist meine Frage:

SELECT t1.ReturnINT, t1.ReturnBIT, t2.ReturnINT, t3.ReturnINT, t5.ReturnINT, t1.ReturnDateTime 
FROM t1 
INNER JOIN t2 
    ON t2.my_column_varchar = t1.my_column_varchar 
INNER JOIN t3 
    ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID 
INNER JOIN t4 
    ON t4.my_column_varchar = t1.my_column_varchar 
INNER JOIN t5 
    ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int 
INNER JOIN t6 
    ON t6.my_column_int = t5.my_column_int AND t6.my_column_int = t2.my_column_int 
INNER JOIN t7 
    ON t7.my_column_int = t6.my_column_int 
INNER JOIN t8 
    ON t8.my_column_int = t3.my_column_int AND t8.my_column_datetime = t1.my_column_datetime 
INNER JOIN t9 
    ON t9.my_column_int = t3.my_column_int AND t8.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2 
INNER JOIN t10 
    ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = t6.my_column_int 
INNER JOIN t11 
    ON t11.my_column_int = t9.my_column_int AND t8.my_column_datetime = t11.my_column_datetime 

---- ---- EDITED

gibt es keine where-Klausel, meine Frage ist genau das, wie ich hier setzen.

Hier sind meine gebrochenen Fragen, ich vergesse, sie hier zu setzen. Es läuft in 3 Minuten.

DECLARE @temp TABLE (
    <Some_columns> 
) 
INSERT INTO @temp 
    SELECT <My_Linked_Columns> 
    FROM t1 
    INNER JOIN t2 
     ON t2.my_column_varchar = t1.my_column_varchar 
    INNER JOIN t3 
     ON t3.my_column_number = t1.my_column_number AND t2.my_column_ID = t3.my_column_ID 
    INNER JOIN t4 
     ON t4.my_column_varchar = t1.my_column_varchar 
    INNER JOIN t5 
     ON t5.my_column_int = t1.my_column_int AND t5.my_column_int = t4.my_column_int AND t2.my_column_int = t5.my_column_int 


DECLARE @temp2 TABLE(
    <Some_Columns> 
) 
INSERT INTO @temp2 
    SELECT <More_Linked_Columns> 
    FROM @temp as temp 
    INNER JOIN t6 
     ON t6.my_column_int = temp.my_column_int AND t6.my_column_int = temp.my_column_int 
    INNER JOIN t7 
     ON t7.my_column_int = t6.my_column_int 
    INNER JOIN t8 
     ON t8.my_column_int = temp.my_column_int AND t8.my_column_datetime = temp.my_column_datetime 


DECLARE @temp3 TABLE(
    <Some_Columns> 
) 
INSERT INTO @temp3 
    SELECT <More_Linked_Columns> 
    FROM @temp2 AS temp2 
    INNER JOIN t9 
     ON t9.my_column_int = temp2.my_column_int AND temp2.my_column_datetime BETWEEN t9.my_column_datetime1 AND t9.datetime1 + t9.my_column_datetime2 
    INNER JOIN t10 
     ON t10.my_column_int = t9.my_column_int AND t10.my_column_int = temp2.my_column_int 
    INNER JOIN t11 
     ON t11.my_column_int = t9.my_column_int AND temp2.my_column_datetime = t11.my_column_datetime 


SELECT <All_Final_Columns> 
FROM @temp3 

---- EDITED 3 ----

mehr Dinge Studium habe ich ein Problem in Ausführungsplan entdeckt. Ich habe eine verschachtelte Schleife, die 1 Zeile schätzt, aber tatsächlich 1.204.014 Zeilen zurückgibt. Ich denke, das Problem genau hier ist, aber ich habe nicht herausfinden, wie dieses Problem zu lösen, ohne meine Frage in 3 Teile zu brechen (jetzt weiß ich, warum es zu brechen ist schneller hehehe)

+2

Dies könnte eine beliebige Anzahl von Dingen sein. Es könnte indizieren, es könnte sein, dass Sie nonSARGable Prädikate haben, wenn es eine where-Klausel gibt, die Liste könnte weiter und weiter gehen. Ohne einige tatsächliche Details gibt es wenig, was jemand tun kann, außer zu erraten, was das langsam macht. –

+1

Es reduziert die Auswahlmöglichkeiten für Optimizer, um die Join-Reihenfolge und den Join-Typ zu bestimmen –

Antwort

2

Die häufigsten Gründe:

Grund 1: Wenn zwei Tabellen n und m Zeilen in INNER JOIN viele zu viele Beziehung beteiligt ist, dann ist die INNER JOIN kann in der Nähe eines CROSS JOIN und produzieren kann mit mehr als MAX (n, m) Zeilen, theoretisch nxm Reihen Ergebnismenge Sind möglich.

Stellen Sie sich nun viele solche Tabellen in INNER JOIN vor.

Dies führt dazu, dass das Ergebnis größer und größer wird und in den zugewiesenen Speicherbereich hineinfriert.

Dies könnte ein Grund sein, warum temporäre Tabellen Ihnen helfen könnten.

Grund 2: Sie haben INDEX nicht auf den Spalten gebaut, die Sie Tabellen beitreten.

Grund 3: Haben Sie Funktionen in WHERE Klausel?

1

Im Allgemeinen möchten Sie, dass der Abfrageoptimierer die Tabellen so verbindet, dass die Ergebnismenge so weit wie möglich begrenzt wird. Wenn Sie die Tabelle A mit 1 Million Zeilen, die Tabelle B mit 1 Million Zeilen und die Tabelle C mit 10 Zeilen haben, möchten Sie die innere Verknüpfung von Tabelle C zuerst mit A oder B durchführen. Dies würde Ihnen höchstens 10 Datensätze geben ein 1: 1-Match), um sich dann dem letzten Tisch anzuschließen. Wenn Sie zuerst von A nach B kamen, würden Sie alle 1 Million Reihen von jedem beitreten, was ziemlich viel länger dauern würde.

Normalerweise ist der Abfrageoptimierer bei der Auswahl der Join-Reihenfolge "gut genug", in Ihrem Fall jedoch nicht.Die beste Methode zum Erzwingen der Join-Reihenfolge wurde von Adam Mechanic in a blog post here demonstriert. Es beinhaltet die Verwendung einer TOP-Klausel in den Tabellen, von denen aus Sie den Join beginnen möchten. Der Abfrageoptimierer wird dann zuerst die Ergebnismenge aus diesen Tabellen abrufen, und Sie können die Gesamtanzahl der Zeilen wirklich begrenzen und die Abfrageleistung erhöhen. Ich benutze diese Methode wann immer möglich.

0

Mit dem richtigen Index oder den richtigen Indizes sollte die ursprüngliche Abfrage sehr schnell ausgeführt werden (mindestens eine Sekunde, wenn Sie die Daten pagen). Verwenden Sie keine temporären Tabellen als Hack, um nicht in der Lage zu sein, eine sinnvolle Anfrage zu stellen.