2010-07-01 8 views
9

Nehmen wir an, wir haben zwei Tabellen: 'Car' und 'Part', mit einer Verbindungstabelle in 'Car_Part'. Sagen wir, ich möchte alle Autos sehen, die einen Teil 123 haben. Ich kann dies tun:Was ist schneller: JOIN mit GROUP BY oder eine Unterabfrage?

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
WHERE Car_Part.Part_Id = @part_to_look_for 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

Oder ich könnte diesen

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE Car.Car_Id IN (SELECT Car_Id FROM Car_Part WHERE Part_Id = @part_to_look_for) 

Jetzt tun, alles, was in mir will die erste Methode verwenden, weil ich oben von gut Eltern gebracht worden bin, der in mir eingeflößt ein Puritanischer Hass auf Sub-Queries und eine Liebe zur Mengenlehre, aber es wurde mir vorgeschlagen, dass das große GROUP BY schlechter ist als eine Sub-Query.

Ich sollte darauf hinweisen, dass wir auf SQL Server 2008 sind. Ich sollte auch sagen, dass in der Realität möchte ich die Teil-ID, Part Type und möglicherweise auch andere Dinge auswählen. Also, die Abfrage, die ich tun möchte, sieht tatsächlich wie folgt aus:

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
INNER JOIN Car_Part ON Car_Part.Car_Id = Car.Car_Id 
INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
WHERE (@part_Id IS NULL OR Car_Part.Part_Id = @part_Id) 
AND (@part_type IS NULL OR Part.Part_Type = @part_type) 
GROUP BY Car.Col1, Car.Col2, Car.Col3 

Oder ...

SELECT Car.Col1, Car.Col2, Car.Col3 
FROM Car 
WHERE (@part_Id IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    WHERE Part_Id = @part_Id)) 
AND (@part_type IS NULL OR Car.Car_Id IN (
    SELECT Car_Id 
    FROM Car_Part 
    INNER JOIN Part ON Part.Part_Id = Car_Part.Part_Id 
    WHERE Part.Part_Type = @part_type)) 
+2

Haben Sie beides ausgeführt? Blick auf die Abfragepläne? Benchmarked es? – Oded

+1

Ich müsste eine Menge Daten generieren, also komme ich erst nächste Woche dazu. Und als ich nach einer Antwort gegoogelt habe, habe ich keine gefunden, also lohnt es sich, online eine Frage für alle anderen zu stellen. – d4nt

+0

Group By ist arbeitsintensiv, verwendet um Dinge wie Durchschnittswerte, Summen usw. zu berechnen. Sie scheinen es zu benutzen, um Dubletten zu eliminieren. Versuchen Sie DISTINCT ohne die Gruppe von ... – Alocyte

Antwort

3

Ich habe ähnliche Daten, also habe ich den Ausführungsplan für beide Arten der Abfrage überprüft. Zu meiner Überraschung erzeugte die Column In Subquery (CIS) einen Ausführungsplan mit 25% weniger E/A-Kosten als die innere Join (IJ) -Abfrage. Im CIS-Ausführungsplan erhalte ich zwei Index-Scans der Zwischentabelle (Car_Part) gegenüber einem Index-Scan des Zwischenprodukts und einen relativ teureren Hash-Join im IJ. Meine Indizes sind gesund, aber nicht geclustert, daher liegt es nahe, dass die Index-Scans durch Clustering etwas schneller gemacht werden. Ich bezweifle, dass dies die Kosten des Hash-Joins beeinflussen würde, was der teurere Schritt in der IJ-Abfrage ist.

Wie die anderen darauf hingewiesen haben, kommt es auf Ihre Daten an. Wenn Sie in diesen 3 Tabellen mit vielen Gigabyte arbeiten, schalten Sie sie ab. Wenn Ihre Zeilen zu Hunderten oder Tausenden nummeriert sind, können Sie Haare über einen sehr kleinen Leistungsgewinn spalten. Ich würde sagen, dass die IJ-Abfrage viel besser lesbar ist, so lange es gut genug ist, tun Sie einem zukünftigen Entwickler, der Ihrem Code einen Gefallen tut und ihnen etwas leichter zu lesen gibt. Die Zeilenanzahl in meinen Tabellen ist 188877, 283912, 13054 und beide Abfragen wurden in kürzerer Zeit zurückgegeben, als es dauerte, einen Kaffee zu trinken.

Kleines Postscript: Da Sie keine numerischen Werte aggregieren, sieht es so aus, als wollten Sie distinct auswählen. Sofern Sie nicht wirklich etwas mit der Gruppe machen, ist es einfacher, Ihre Absicht am Ende mit einer bestimmten Gruppe als einer Gruppe zu sehen.IO-Kosten ist die gleiche, aber eine zeigt Ihre Absicht besser IMHO.

4

Das Beste, was Sie tun können, ist, sie selbst testen, auf realistischen Datenmengen. Das würde nicht nur für diese Abfrage, sondern für alle zukünftigen Abfragen nützlich sein, wenn Sie nicht sicher sind, welcher der beste Weg ist.

Wichtige Dinge zu tun sind:
- Test auf Produktionsdatenmengen
- Test ziemlich & konsequent (clear cache: http://www.adathedev.co.uk/2010/02/would-you-like-sql-cache-with-that.html)
- überprüfen den Ausführungsplan

Sie könnten entweder Monitor SQL Profiler und überprüfen Sie die Dauer/liest/schreibt/CPU dort, oder SET STATISTICS IO ON; SET STATISTICS TIME ON;, um Statistiken in SSMS auszugeben. Vergleichen Sie dann die Statistiken für jede Abfrage.

Wenn Sie diese Art von Tests nicht durchführen können, werden Sie sich möglicherweise später Leistungsproblemen aussetzen, die Sie dann tunen/beheben müssen. Es gibt Tools, die Sie verwenden können, die Daten für Sie generieren werden.

2

Mit SQL Server 2008 würde ich erwarten, In schneller zu sein, da es äquivalent ist.

d. H. Es muss nur auf das Vorhandensein der Zeile prüfen, nicht beitreten, dann entfernen Sie die Duplikate. Dies ist discussed here.