2016-04-11 8 views
3

Angenommen, wir haben 4 Tabellen A, B, C, D in einige nicht näher angegebenen relationalen SQL-Datenbank. A Referenzen B, auch C und D. Referenzen bedeutet, dass A die Spalte A.refX_id = X.id hat, X ist A, B und C (gemeinsamer Fremdschlüssel 1: N).SELECT ... WHERE IN vs JOIN

Was ich will, ist Abfrage der Tabelle A mit der Bedingung basierend auf Spalten aus allen untergeordneten Tabellen B, C und D. Meine Frage ist: Welche der folgenden Varianten ist im Allgemeinen besser? (. In Bezug auf Benutzerfreundlichkeit, Effizienz, Geschwindigkeit)

Variante 1:

SELECT DISTINCT A.* FROM A 
    JOIN B ON A.refB_id = B.id 
    JOIN C ON A.refC_id = C.id 
    JOIN D ON A.refD_id = D.id 
    WHERE <condition on B> AND <condition on C> AND <condition on D>; 

Was ich mehr von einer Datenbank aus Sicht mag, sieht aber ein wenig zu Programm härter.

Variante 2:

SELECT id FROM B WHERE <condition on B>; # result store to array "BIds" on program side 
SELECT id FROM C WHERE <condition on C>; # result store to array "CIds" on program side 
SELECT id FROM D WHERE <condition on D>; # result store to array "DIds" on program side 

SELECT A.* FROM A 
    WHERE refB_id IN (<B_ids>) AND refC_id IN (<C_ids>) AND refD_id IN (<D_ids>); 

# <B_ids> menas expand whole array of ids, which can result in a very long query string 

Ich dachte, dass Variante 2 completelly Schmutz und unbrauchbar mit potenziell großen Daten ist. Aber ich habe gehört, dass viele Frameworks es normalerweise benutzen, weil es relativ einfach ist. Ist es eine Art legaler Weg, solche Daten im allgemeinen Fall abzufragen, wenn ich weiß, dass der Inhalt der "IN" -Klausel von einem Ergebnis einer anderen Abfrage (n) genommen wird?

+0

War gerade diese Frage suchen und fand diese Antwort: http://stackoverflow.com/questions/121631/inner-join-vs-wo? rq = 1 – CodeJockey

Antwort

3

passen und bewegen Ich möchte Sie ermutigen IN oder EXISTS zu verwenden:

SELECT A.* 
FROM A 
WHERE EXISTS (SELECT 1 FROM B WHERE A.refB_id = B.id AND <condition on B>) AND 
     EXISTS (SELECT 1 FROM C WHERE A.refC_id = C.id AND <condition on C>) AND 
     EXISTS (SELECT 1 FROM D WHERE A.refD_id = D.id AND <condition on D>); 

Vorteile dieses Ansatzes:

  • Keine Gefahr, große kartesische Zwischenprodukte zu bekommen.
  • Keine Kosten für die Eliminierung von Duplikaten für SELECT DISTINCT. Die meisten Datenbanken behandeln EXISTS ziemlich gut.
  • Sie können jede Unterabfrage mit Indizes optimieren.

EDIT:

Sie können dies schreiben mit IN und Subqueries:

SELECT A.* 
FROM A 
WHERE A.refB_id IN (SELECT B.id FROM B WHERE <condition on B>) AND 
     A.refC_id IN (SELECT C.id FROM C WHERE <condition on C>) AND 
     A.refD_id IN (SELECT D.id FROM D WHERE <condition on D>); 
+0

Vielen Dank! Habe noch nie SELECT 1 gesehen ... Wie würde es mit IN aussehen? Meinst du das Variante1? – David

+0

Ja, das ist lesbarer. Danke, das ist genau das, was ich wollte. – David

+0

@David Ich stimme der Lesbarkeit nicht zu, aber es hängt davon ab, was Sie gewohnt sind zu sehen. – CodeJockey

3

Nicht sicher, welches Framework den zweiten Ansatz verwendet, aber der erste Ansatz ist, was ich anstreben werde und außerdem wird jeder andere es tun. Wenn Sie einen korrekten Index für alle Tabellen in der Join-Spalte erstellt haben, dann ergibt der erste Ansatz einen viel besseren Plan als der zweite, weil Sie mehrere IN-Klausel haben und was, wenn jeder IN an Millionen von Elementen arbeiten muss ???.

Außerdem würde ich die INNER JOIN-LEFT JOIN unter der Annahme ändern, dass nicht alle IDs können die WHERE Bedingungen JOIN ON Bedingungen wie

SELECT DISTINCT A.* FROM A 
    LEFT JOIN B ON A.refB_id = B.id AND <condition on B> 
    LEFT JOIN C ON A.refC_id = C.id AND <condition on C> 
    LEFT JOIN D ON A.refD_id = D.id AND <condition on D>;