2009-01-14 10 views
11

ich eine SQL-Abfrage verwenden, die in die folgende Form ähnelt:LEFT OUTER JOIN auf zwei Säulen Leistungsproblem

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
AND table1.period = table2.period 

Und es ist entweder viel zu langsam oder Deadlocks etwas ist, weil es mindestens 4 Minuten dauert Rückkehr. Wenn ich es zu diesem ändern würde:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table1.period = table2.period 

dann funktioniert es gut (wenn auch nicht die richtige Anzahl von Spalten zurückgeben). Gibt es eine Möglichkeit, dies zu beschleunigen?

UPDATE: Es macht das Gleiche, wenn ich die letzten beiden Zeilen der letzteren Abfrage wechseln:

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.period = table2.period 
WHERE table1.person_uid = table2.person_uid 

UPDATE 2: Diese Ansichten sind eigentlich, dass ich beitreten. Leider befinden sie sich in einer Datenbank, über die ich keine Kontrolle habe. Daher kann ich (leicht) keine Änderungen an der Indexierung vornehmen. Ich bin geneigt zuzustimmen, dass dies ein Indizierungsproblem ist. Ich werde eine Weile warten, bevor ich eine Antwort akzeptiere, für den Fall, dass es eine magische Möglichkeit gibt, diese Frage abzustimmen, von der ich nichts weiß. Ansonsten werde ich eine der aktuellen Antworten akzeptieren und versuchen, einen anderen Weg zu finden, um das zu tun, was ich tun möchte. Danke für die Hilfe von allen bis jetzt.

+0

Bitte geben Sie den Ausführungsplan für diese Abfrage – squadette

Antwort

16

Beachten Sie, dass die Anweisungen 2 und 3 sich von denen der ersten unterscheiden.

Wie? Nun, Sie machen einen linken Outer-Join und Ihre WHERE-Klausel berücksichtigt dies nicht (wie die ON-Klausel). Versuchen Sie mindestens:

SELECT col1, col2 
FROM table1, table2 
WHERE table1.person_uid = table2.person_uid (+) 
AND table1.period = table2.period (+) 

und sehen Sie, ob Sie das gleiche Leistungsproblem erhalten.

Welche Indizes haben Sie für diese Tabellen? Wird diese Beziehung durch eine Fremdschlüsseleinschränkung definiert?

Was Sie wahrscheinlich brauchen, ist ein zusammengesetzter Index sowohl für person_uid als auch für period (in beiden Tabellen).

+0

Diese Abfrage Fehler, die ich nicht mischen kann ANSI Outer Joins und alten Stil Outer Joins. –

+0

Korrigiert. Versuch das. – cletus

+1

Mit Ihren ursprünglichen Abfragen mit dem WHERE konnte die Datenbank frei von table2 fetching table1-Einträge fahren, in denen person_uid oder period übereinstimmt. Die ursprüngliche Abfrage muss Tabelle 1 vollständig scannen und wird schlecht ausgeführt, wenn der Zugriff auf Tabelle 2 schlecht ist (z. B. kein nützlicher Index). –

3

Haben Sie die Deckungsindizes person_uid und period für beide Tabellen?

Wenn nicht, fügen Sie sie hinzu und versuchen Sie es erneut.

Werfen Sie einen Blick auf den Ausführungsplan und sehen Sie, was die Abfrage tatsächlich macht.

Auch: Was sind die Datentypen der Felder? Sind sie in beiden Tabellen gleich? Eine implizite Besetzung kann die Dinge wirklich verlangsamen.

+0

Ähm, die Frage ist markiert Oracle, also glaube ich nicht, dass er SQL Server verwendet. – cletus

+0

Ah :) Ich habe das nicht gesehen ... Egal ... Der Ausführungsplan ist auch in Oracle verfügbar ... Ich werde die Antwort bearbeiten. –

2

Haben diese Tabellen Indizes für die Spalten, denen Sie beitreten? Installieren Sie das kostenlose SQLDeveloper-Produkt von Oracle und verwenden Sie es, um eine "Erklärung" zu dieser Abfrage zu erstellen und festzustellen, ob es sequenzielle Scans beider Tabellen durchführt.

5

Ich denke, Sie müssen verstehen, warum die letzten beiden nicht die gleiche Abfrage wie die erste sind. Wenn Sie einen linken Join ausführen und dann eine where-Klausel hinzufügen, die auf ein Feld in der Tabelle auf der rechten Seite des Joins verweist (derjenige, der möglicherweise nicht immer einen Datensatz zur ersten Tabelle hat), dann haben Sie den Join tatsächlich geändert eine innere Verbindung.Es gibt eine Ausnahme von dieser Regel und das ist, wenn Sie so etwas wie

SELECT col1, col2 
FROM table1 
LEFT OUTER JOIN table2 
ON table1.person_uid = table2.person_uid 
WHERE table2.person_uid is null 

In diesem Fall können Sie für den Datensatz zu fragen Referenz, die keinen Datensatz in der zweiten Tabelle hat. Aber anders als in diesem speziellen Fall ändern Sie den linken Join zu einem inneren Join, wenn Sie in der where-Klausel in table2 ein Feld angeben.

Wenn Ihre Abfrage nicht schnell genug ist, würde ich Ihre Indizierung betrachten.

2

In einem linken Join würden Sie table1 nach jeder eindeutigen Kombination von (person_uid, Punkt) durchsuchen und dann table2 nach allen entsprechenden Datensätzen suchen. Wenn Tabelle 2 keinen geeigneten Index besitzt, kann dies auch das Scannen der gesamten Tabelle beinhalten.

Meine beste Vermutung, ohne einen Ausführungsplan zu sehen, ist, dass die erste Abfrage (die einzige, die korrekt zu sein scheint) die Tabellen Tabelle2 und Tabelle1 zu durchsuchen hat.

Da Sie sagen, dass Sie die Indizes nicht ändern können, müssen Sie die Abfrage ändern. Soweit ich das beurteilen kann, gibt es nur eine realistische Alternative ...

SELECT 
    col1, col2 
FROM 
    table2 
FULL OUTER JOIN 
    table1 
     ON table1.person_uid = table2.person_uid 
     AND table1.period = table2.period 
WHERE 
    table1.person_uid IS NOT NULL 

Die hier Hoffnung ist, dass Sie table2 für jede einzelne Kombination von (person_uid, Zeit) zu scannen, aber die Verwendung von Indizes für tabelle1 machen. (Im Gegensatz zum Scannen von Tabelle1 und Verwenden von Indizes für Tabelle2, was ich von Ihrer Abfrage erwartet habe.)

Wenn Tabelle1 nicht über geeignete Indizes verfügt, wird es jedoch sehr unwahrscheinlich sein, dass sich die Leistung verbessert alle ...

Dems.

4

Alles, was jemand Ihnen basierend auf den von Ihnen angegebenen Informationen sagt, ist eine Vermutung.

Sehen Sie sich den Ausführungsplan für die Abfrage an. Wenn Sie keinen Grund für die Langsamkeit des Plans sehen, schreiben Sie den Plan hier.

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/ex_plan.htm#PFGRF009

+1

@Dave Costa: Absolut! Verwenden Sie den Oracle-Trace, um den Ausführungsplan und das, worauf Oracle wartet, herauszufinden. Abwesend, jeder rät nur. – spencer7593

+0

http://download.oracle.com/docs/cd/B28359_01/server.111/b28274/sqltrace.htm – spencer7593

0

In einem der Updates stellt der OP, dass er tatsächlich Ansichten nicht Tabellen abfragt wird. In diesem Fall könnte die Leistung verbessert werden, indem die Tabellen, die er benötigt, direkt abgefragt werden, insbesondere wenn die Ansichten komplex sind und zu vielen anderen Tabellen gehören, die keine Informationen enthalten, die er benötigt, oder sie sind Ansichten, die Aufrufe aufrufen.

0

ANSI Join-Syntax bietet eine sehr klare Unterscheidung zwischen JOIN-Bedingungen und FILTER Prädikate; Dies ist sehr wichtig beim Schreiben von Outer Joins. Mit den emp/dept Tabellen, Blick auf die Ergebnisse aus der folgenden zwei Outer-Joins

Q1

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
and loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
RESEARCH    20      DALLAS 
SALES     30      CHICAGO 
OPERATIONS    40      BOSTON 

====

Q2 
SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
LEFT OUTER JOIN emp e 
on d.deptno = e.deptno 
where loc in ('NEW YORK','BOSTON') 
; 

DNAME    DEPTNO ENAME    MGR LOC 
-------------- ---------- ---------- ---------- ------------- 
ACCOUNTING    10 CLARK   7839 NEW YORK 
ACCOUNTING    10 KING     NEW YORK 
ACCOUNTING    10 MILLER   7782 NEW YORK 
OPERATIONS    40      BOSTON 

Das erste Beispiel, Q1 zeigt ein Beispiel für "sich einer Konstante anschließen". Im Wesentlichen wird die Filterbedingung angewendet, bevor die äußere Verknüpfung ausgeführt wird. So eliminieren Sie Zeilen, die anschließend als Teil der äußeren Verknüpfung hinzugefügt werden. Es ist nicht unbedingt falsch, aber ist das die Frage, nach der Sie wirklich gefragt haben? Häufig sind die in Q2 gezeigten Ergebnisse erforderlich, bei denen der Filter nach der (äußeren) Verknüpfung angewendet wird.

Es gibt auch eine Performance-Implikation für große Datenmengen.In vielen Fällen muss der Beitritt zu einer Konstanten intern vom Optimierer gelöst werden, indem eine laterale Ansicht erstellt wird, die normalerweise nur über einen Nested-Loop-Join statt über einen Hash-Join optimiert werden kann. Für Entwickler, die mit Oracle vertraut sind Outer Joinsyntax würde die Abfrage wahrscheinlich geschrieben worden als

SELECT dname, d.deptno, e.ename, e.mgr, d.loc 
FROM dept d 
     ,emp e 
where d.deptno = e.deptno(+) 
and loc in ('NEW YORK','BOSTON') 

Diese Abfrage ist semantisch äquivalent wie Q2 oben.

Zusammenfassend ist es äußerst wichtig, dass Sie die Unterschiede zwischen der JOIN-Klausel und der WHERE-Klausel verstehen, wenn Sie ANSI-Outer-Joins schreiben.