2011-01-14 4 views
1

Ich habe eine vorherige Frage hier gefragt, was war besser, JOIN Abfragen oder Abfragen mit Subselects. Link: Queries within queries: Is there a better way?Benötigen Sie Hilfe beim Verständnis der SQL-Erklärung einer JOIN-Abfrage im Vergleich zu einer Abfrage mit Subselects

Dies ist eine Erweiterung dieser Frage. Kann mir jemand erklären, warum ich sehe, was ich hier sehe?

Query (Subselects):

SELECT article_seq, title, synopsis, body, lastmodified_date, (SELECT type_id FROM types WHERE kbarticles.type = type_seq), status, scope, images, archived, author, owner, (SELECT owner_description FROM owners WHERE kbarticles.owner = owner_seq), (SELECT review_date FROM kbreview WHERE kbarticles.article_seq = article_seq) FROM kbarticles WHERE article_seq = $1 

Analysieren Explain (Subselects)

QUERY PLAN 

Index Scan using article_seq_pkey on kbarticles (cost=0.00..32.24 rows=1 width=1241) (actual time=1.421..1.426 rows=1 loops=1) 

    Index Cond: (article_seq = 1511) 

    SubPlan 

    -> Seq Scan on kbreview (cost=0.00..14.54 rows=1 width=8) (actual time=0.243..1.158 rows=1 loops=1) 

      Filter: ($2 = article_seq) 

    -> Seq Scan on owners (cost=0.00..1.16 rows=1 width=24) (actual time=0.073..0.078 rows=1 loops=1) 

      Filter: ($1 = owner_seq) 

    -> Index Scan using types_type_seq_key on types (cost=0.00..8.27 rows=1 width=24) (actual time=0.044..0.050 rows=1 loops=1) 

      Index Cond: ($0 = type_seq) 

Total runtime: 2.051 ms 

Query (JOIN s)

SELECT k.article_seq, k.title, k.synopsis, k.body, k.lastmodified_date, t.type_id, k.status, k.scope, k.images, k.archived, k.author, k.owner, o.owner_description, r.review_date FROM kbarticles k JOIN types t ON k.type = t.type_seq JOIN owners o ON k.owner = o.owner_seq JOIN kbreview r ON k.article_seq = r.article_seq WHERE k.article_seq = $1 

Analysieren Erklären (JOIN s)

QUERY PLAN 

Nested Loop (cost=0.00..32.39 rows=1 width=1293) (actual time=0.532..1.467 rows=1 loops=1) 

    Join Filter: (k.owner = o.owner_seq) 

    -> Nested Loop (cost=0.00..31.10 rows=1 width=1269) (actual time=0.419..1.345 rows=1 loops=1) 

     -> Nested Loop (cost=0.00..22.82 rows=1 width=1249) (actual time=0.361..1.277 rows=1 loops=1) 

       -> Index Scan using article_seq_pkey on kbarticles k (cost=0.00..8.27 rows=1 width=1241) (actual time=0.065..0.071 rows=1 loops=1) 

        Index Cond: (article_seq = 1511) 

       -> Seq Scan on kbreview r (cost=0.00..14.54 rows=1 width=12) (actual time=0.267..1.175 rows=1 loops=1) 

        Filter: (r.article_seq = 1511) 

     -> Index Scan using types_type_seq_key on types t (cost=0.00..8.27 rows=1 width=28) (actual time=0.048..0.055 rows=1 loops=1) 

       Index Cond: (t.type_seq = k.type) 

    -> Seq Scan on owners o (cost=0.00..1.13 rows=13 width=28) (actual time=0.022..0.038 rows=13 loops=1) 

Total runtime: 2.256 ms 

Basierend gegeben auf den Antworten (und akzeptiert) in meiner vorherigen Frage sollte JOIN s bessere Ergebnisse haben, unter Beweis stellen. In all meinen Tests sehe ich jedoch JOIN s, die um einige Millisekunden schlechtere Ergebnisse liefern. Es scheint auch, dass die JOIN s mit verschachtelten Schleifen gespickt sind. Alle Tabellen, die ich bin, sind indexiert.

Mache ich etwas, was ich anders machen sollte? Gibt es etwas, das mir fehlt?

+0

Wie viele Zeilen haben diese Tabellen? Unterabfrage kann bei geringer Zeilenanzahl schneller sein ... Haben Sie 10.000 Zeilen oder mehr probiert? –

Antwort

2

Diese Abfragen sind logisch unterschiedlich.

Die erste:

SELECT article_seq, title, synopsis, body, lastmodified_date, 
     (
     SELECT type_id 
     FROM types 
     WHERE kbarticles.type = type_seq 
     ), 
     status, scope, images, archived, author, owner, 
     (
     SELECT owner_description 
     FROM owners 
     WHERE kbarticles.owner = owner_seq 
     ), 
     (
     SELECT review_date 
     FROM kbreview 
     WHERE kbarticles.article_seq = article_seq 
     ) 
FROM kbarticles 
WHERE article_seq = $1 

Die zweite:

SELECT k.article_seq, k.title, k.synopsis, k.body, k.lastmodified_date, t.type_id, k.status, 
     k.scope, k.images, k.archived, k.author, k.owner, o.owner_description, r.review_date 
FROM kbarticles k 
JOIN types t 
ON  k.type = t.type_seq 
JOIN owners o 
ON  k.owner = o.owner_seq 
JOIN kbreview r 
ON  k.article_seq = r.article_seq 
WHERE k.article_seq = $1 

Wenn es mehr als einen Datensatz in types, owners oder kbreview ist, die erste Abfrage fehlschlagen, während der zweite wird Duplikate von kbarticles zurückgeben.

Wenn es keine types ist, owners oder kbreviews für eine kbarticle, die erste Abfrage eine NULL in dafür vorgesehene Feld zurückzukehren, während der zweite wird nur diesen Datensatz auslassen.

Wenn die Felder *_seq scheinen, die PRIMARY KEY Felder zu sein, wird es nie doppelte und die Abfrage wird nie fehlschlagen; Auf die gleiche Weise, wenn kbarticles mit FOREIGN KEY Referenzen auf types, owners oder eingeschränkt ist, kann es keine fehlenden Zeilen geben.

jedoch JOIN Betreiber geben dem Optimierer mehr Platz: es jeden Tisch führende machen und erweitern JOIN Techniken wie HASH JOIN oder MERGE JOIN zu benutzen, die nicht verfügbar sind, wenn Sie Unterabfragen verwenden.

+0

Also, im Grunde sagen Sie, ich sollte wahrscheinlich mit 'JOIN's bleiben, da sie auf lange Sicht mehr Vorteile bieten und wirklich ein paar Millisekunden vernachlässigbar machen. –

+0

@Michael: wie gesagt, diese Abfragen sind logisch unterschiedlich. Sie sind nur dann gleich, wenn beide Bedingungen, die ich erwähne, gelten: '* _seq' Felder sind' PRIMARY KEY' und Sie haben 'FOREIGN KEY' Einschränkungen für' kbarteil', die auf alle verweisen. Wenn sie das nicht tun (und das ist höchstwahrscheinlich nicht der Fall, da 'kbreview.article_seq' anscheinend kein' PRIMARY KEY' ist), dann sollten Sie sich aussuchen, welche von denen Sie wollen. Kannst du mehr als eine Rezension pro Artikel haben? Wenn Sie können, schlägt die erste Abfrage für Artikel mit mehr als einer Überprüfung fehl. – Quassnoi

+0

'kbreview.article_seq' ist sicher kein Primärschlüssel. Es gibt eine weitere Spalte mit einem eindeutigen Primärschlüssel für die Tabelle 'kbreview'. 'Kbreview.article_seq' ist jedoch definitiv eindeutig und sollte niemals doppelte Werte enthalten. Ich habe bemerkt, dass der Index, den ich in dieser Spalte erstellt habe, nicht die einzige Einschränkung dafür hat, und das habe ich jetzt behoben. –

0

Ist diese Tabellenspalte indiziert? r.article_seq

-> Seq Scan auf kbreview r (cost = 0.00..14.54 rows = 1 width = 12) (Istzeit = 0.267..1.175 rows = 1 Schleifen = 1)

Hier wird die meiste Zeit verbracht.

+0

Ja, es gibt einen Index für diese Spalte. 'kbreview_article_seq \t CREATE INDEX kbreview_article_seq ON kbreview BENUTZEN btree (article_seq)' –

0

Angesichts der Tatsache, dass beide Pläne die gleichen Tabellen-Scans, nur auf eine andere Weise angeordnet, würde ich sagen, dass es keinen signifikanten Unterschied zwischen den beiden gibt. Eine "verschachtelte Schleife", bei der der untere Arm eine einzelne Zeile erzeugt, entspricht in etwa einem einreihigen Subselect.

Joins sind allgemeiner, da die Verwendung von skalaren Subselects sich nicht auf zwei Spalten aus diesen Hilfstabellen erstreckt.

Verwandte Themen