2009-07-08 3 views
6

Ich ziehe es vor, in t-sql mit dem Code zu codieren, der tatsächlich ein Inline-Join ist, anstatt eine lange Liste der Joins am Ende der Stored Procedure oder View zu haben.Welche der beiden Arten, einen Inner Join zu codieren, ist schneller?

Zum Beispiel habe ich Code:

SELECT  PKey , Billable, 
    (SELECT LastName FROM Contact.dbo.Contacts WHERE (Pkey = Contacts_PKey)), 
    (SELECT Description FROM Common.dbo.LMain WHERE (PKey= DType)), 
    (SELECT TaskName FROM Common.dbo.LTask WHERE (PKey = TaskType)) , 
    StartTime, EndTime, SavedTime 
FROM dbo.TopicLog where StartTime > '7/9/09' ORDER BY StartTime 

Statt

SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime 
FROM dbo.TopicLog AS t  
inner join Contact.dbo.Contacts as c on c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09' 
inner join Common.dbo.LMain as m on m.PKey = t.DType 
inner join Common.dbo.LTask as lt on lt.PKey = t.TaskType 
ORDER BY t.StartTime 

ich diese Art von Syntax bevorzugen, weil es so viel weniger verwirrend ist, wenn oder Fehlersuche zu schreiben, vor allem, wenn es viele Tische verbunden sein oder andere Sachen, die weitergehen (Fallanweisungen, t-sql-Funktionen, Selbstverbindungen usw.)

Aber meine Frage ist - nehme ich eine Leistung, die durch das Abfragen der Datenbank getroffen wird se auf diese Weise.

Ich habe noch nicht genug Daten gesammelt, um einen Unterschied zu messen, aber ich werde irgendwann die Straße runter gehen.

Ich würde gerne herausfinden, bevor ich weiter fortfahren. Ich möchte nicht später zurückgehen und alles neu programmieren müssen, um die Leistung zu verbessern.

Antwort

20

Die zweite (die tatsächliche innere Verbindung), im Allgemeinen. Die erste (Unterabfragen) führt 3 Abfragen für jede Zeile durch, aber diese wird im Allgemeinen vom Compiler verwaltet, so dass die Unterschiede gemildert werden.

Beste noch: Check the query execution plans für sich selbst!

Da Sie langsam Leistung erhalten, ist meine Vermutung, dass Ihre Tabellen nicht ordnungsgemäß indiziert sind. Sie sollten Clustered-Indizes für alle Ihre Primärschlüssel und nicht gruppierte Indizes für die Fremdschlüssel (diejenigen, die Sie zum Herstellen der Joins verwenden) haben.

Ich sollte beachten, dass diese beiden Abfragen genau dann gleichwertig sind, wenn Sie in allen Ihren Join-Bedingungen übereinstimmende Werte haben (d. H. - gibt immer alle Zeilen aus der Haupttabelle zurück). Andernfalls erhalten Sie null aus der Unterabfrage, wenn keine Übereinstimmung vorliegt. Interne Joins filtern aktiv alle Zeilen heraus, die nicht mit den Join-Bedingungen übereinstimmen. Der Unterabfrage-Ansatz ist tatsächlich äquivalent (in Ergebnissen, nicht Geschwindigkeit oder Ausführung) zu einem linken äußeren Join.

+1

+1. Wie Sie unterstreichen, sind die Gewinne, die durch sorgfältige Indexierung erzielt werden, viel wahrscheinlicher, um signifikante Gewinne zu erzielen. (Aber die Überprüfung des Ausführungsplans wird sie sicher wissen!) – Beska

+2

+1 "Überprüfen Sie die Abfrage Ausführungspläne für sich selbst!" Nur so kann man sicher sein. Der Optimierer * könnte sie * automatisch in JOINs verwandeln. Obwohl die zwei Abfragen nicht genau identisch sind. # 1 ist ein LINKER JOIN, # 2 ist ein INNERER JOIN. Also werden sie dir trotzdem andere Pläne geben. – beach

+0

Dies ist ziemlich irreführend - es ist ein weit verbreiteter Irrtum, dass die Unterabfragen aus dem angegebenen Grund langsamer sind, wobei SQL Server tatsächlich Unterabfragen als Joins beschreibt, die bei der Neukompilierung ohnehin möglich sind. – Justin

0

Im Allgemeinen sind Sub-Abfragen (dh erstes Beispiel) langsamer, aber der einfachste Weg, um Ihre Abfragen zu optimieren und zu analysieren, ist, sie durch Ihre spezifische Datenbank zu testen. MS SQL Server bietet exzellente Analyse- und Performance-Tuning-Tools.

+0

Das ist einfach nicht wahr - SQL-Server parst häufig Unterabfragen in einen Ausführungsbaum, der mit dem von einem Join erzeugten identisch ist. – Justin

10

Die erste Methode ist überhaupt keine innere Verknüpfung, es ist eine korrelierte Unterabfrage. Und sie sind eher linke Outer-Joins als innere Joins, da sie NULL zurückgeben, wenn es keinen übereinstimmenden Wert gibt.

3

Der erste sieht wie eine pathologische Art aus, mich zu verbinden. Ich würde es vermeiden, wenn aus einem anderen Grund, dass es ungewöhnlich ist - ein erfahrener SQL DBA, der es betrachtet, um es zu behalten, wird eine Weile nach dem Grund suchen, warum es so codiert ist, wenn es keinen wirklichen Grund gibt, was Sie tun will die Abfrage zu tun. Es verhält sich eher wie ein äußerer Join, wenn Daten fehlen.

Das zweite Beispiel sieht normal aus.

Sie sollten wissen, dass die alten Schulweg Innen tun verbindet, ist wie folgt:

SELECT t.PKey, t.Billable, 
c.LastName, m.Description, lt.TaskName, 
t.StartTime, t.EndTime, t.SavedTime 
FROM 
dbo.TopicLog as t, Contact.dbo.Contacts as c, 
Common.dbo.LMain as m, Common.dbo.LTask as lt 
WHERE c.Pkey = t.Contacts_PKey and t.StartTime > '7/9/09' 
    AND m.PKey = t.DType 
    AND lt.PKey = t.TaskType 
ORDER BY t.StartTime 

Und bei einer Vermutung dies entspricht dem modernen „INNER JOIN Tabelle auf Feld“ Syntax sobald es geparst wurde.

Wie die andere Antwort sagt, wenn Sie nach schnelleren Abfragen suchen, ist das erste, was zu tun ist, zu überprüfen, ob die Indizes der Tabellen aussortiert sind. Sehen Sie sich den Abfrageausführungsplan an.

+0

Es scheint, als ob diese Syntax das ist, wonach er sucht. Indizes oder keine Indizes, die Unterabfragen für jede ausgewählte Zeilentabelle ausführen, werden selbst für eine kleine Tabelle langsam sein (wie mehr als etwa 4000 Zeilen). – Jon

0

Viele SQL-Programmierer sind sich völlig nicht bewusst, dass das Optimierungsprogramm häufig Unterabfragen in Joins auflöst. Es gibt wahrscheinlich keinen Grund für Leistungsprobleme in beiden Abfragen.

Sehen Sie sich den Ausführungsplan an!

1

Die beiden Abfragen im OP sagen sehr verschiedene Dinge, und produziert nur die gleichen Ergebnisse, wenn das Modell richtigen Daten Annahmen getroffen werden:

  1. Jeder der in der Suche verwendeten Spalten nicht null Einschränkungen und Fremdschlüsseleinschränkungen.

  2. Der Primärschlüssel oder ein eindeutiger Schlüssel der Nachschlagetabelle wird verwendet.

Es kann im OP spezifischen Fall sein, diese Annahmen zutreffen, aber in dem allgemeinen Fall ist dies anders.

Wie andere darauf hingewiesen haben, ist die Unterabfrage mehr wie ein Outer Join in dem es eine Null für die Spalten LastName, Description und Taskname zurückgibt, anstatt die Zeile vollständig herauszufiltern.

Wenn eine der Unterabfragen mehr als eine Zeile zurückgibt, erhalten Sie einen Fehler.

Soweit persönliche Präferenz, bevorzuge ich das zweite Beispiel mit der Join-Syntax, aber das ist subjektiv.

0

Ich denke, der zweite wird schneller ausgeführt. Grund dafür ist die Verwendung von Alias ​​(t, c, m usw. in Ihrem Beispiel) Name relationale Engine kann leicht den Zeiger auf den Speicherort der Tabelle finden.

Ich denke, das ist einer der Tipps in SQL Tunning.

1

Allgemein gesprochen gibt es keinen Unterschied bei der Durchführung von einfachen Unterabfragen vs schließt sich - es ist ein verbreiteter Irrtum ist, die Unterabfragen sind viel langsamer (da SQL Server einer Schleife durch die innere Abfrage hat), was jedoch im Allgemeinen ist einfach nicht wahr! Während des Kompilierungsprozesses erzeugt SQL Server eine Ausführungsstruktur, und in diesen Bäumen entsprechen Unterabfragen häufig Joins.

Sein bemerkenswert, dass Ihre beiden Abfragen nicht logisch gleich sind und produziert für mich unterschiedliche Ergebnisse, lesen Sie die zweite Abfrage sollte eigentlich etwas entlang der Linien von: (dies immer noch identisch ist nicht, aber seine näher)

SELECT t.PKey, t.Billable, c.LastName, m.Description, lt.TaskName, t.StartTime, t.EndTime, t.SavedTime 
FROM dbo.TopicLog AS t  
LEFT OUTER JOIN Contact.dbo.Contacts as c on c.Pkey = t.Contacts_PKey 
LEFT OUTER JOIN Common.dbo.LMain as m on m.PKey = t.DType 
LEFT OUTER JOIN Common.dbo.LTask as lt on lt.PKey = t.TaskType 
WHERE t.StartTime > '7/9/09' 
ORDER BY t.StartTime 

In meiner Prüfung erstellt die Unterabfrage einen Ausführungsplan mit einer drastisch niedrigeren Anzahl von Lesevorgängen (15 im Gegensatz zu 1000), jedoch etwas höhere CPU - im Durchschnitt waren die Ausführungszeiten etwa gleichwertig.

Es ist jedoch bemerkenswert, dass dies nicht immer der Fall sein wird (insbesondere bei der Auswertung von Funktionen in einer Unterabfrage), und manchmal können Sie Probleme aufgrund einer Unterabfrage auftreten. Im Allgemeinen ist es jedoch am besten, sich nur dann um solche Fälle zu kümmern, wenn es zu Leistungsproblemen kommt.