LEFT OUTER JOIN auf zwei Säulen Leistungsproblem
Frage
Ich bin mit einer SQL-Abfrage, die die folgenden Form ähnelt:
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 zurückzukehren. Wenn ich es, dies zu ändern:
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ückkehren). Gibt es eine Möglichkeit, dies zu beschleunigen?
UPDATE : Es tut die gleiche Sache, 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 sind eigentlich sieht, dass ich beitreten. Leider sind sie in einer Datenbank Ich habe keine Kontrolle über, so kann ich nicht (leicht) an die Indizierung Änderungen vornehmen. Ich bin geneigt, dem zuzustimmen, dass dies eine obwohl Indizierung Problem. Ich werde ein wenig warten, bevor eine Antwort für den Fall der Annahme, dass eine magische Art und Weise ist diese Abfrage zu stimmen, die ich nicht kenne. Ansonsten werde ich eine der aktuellen Antworten akzeptieren und versuchen, einen anderen Weg, um herauszufinden, zu tun, was ich tun will. Vielen Dank für die Hilfe der jeder so weit.
Lösung
Beachten Sie, dass Aussagen 2 und 3 zum ersten unterschiedlich sind.
Wie? Nun, Sie tun, eine linke äußere Verknüpfung und WHERE-Klausel nicht, dass unter Berücksichtigung der (wie die ON-Klausel der Fall ist). Zumindest versuchen:
SELECT col1, col2
FROM table1, table2
WHERE table1.person_uid = table2.person_uid (+)
AND table1.period = table2.period (+)
und sehen Sie, wenn Sie die gleiche Leistung Ausgabe erhalten.
Welche Indizes haben Sie auf diese Tabellen? Ist diese Beziehung durch einen Fremdschlüssel definiert?
Was Sie wahrscheinlich brauchen, ist ein Composite-Index sowohl auf person_uid und Zeit (auf beiden Tabellen).
Andere Tipps
Ich glaube, Sie müssen verstehen, warum die letzten beide nicht die gleiche Abfrage wie die ersten sind. Wenn Sie ein linkes treten und fügen Sie dann ein where-Klausel ein Feld in der Tabelle auf der rechten Seite des Join referncing (die, die nicht immer einen Datensatz können die erste Tabelle entsprechen), dann haben Sie effektiv die Verbindung geändert eine innere Verknüpfung. Es gibt eine Ausnahme von dieser Regel und das ist, wenn Sie so etwas wie
ReferenzSELECT col1, col2
FROM table1
LEFT OUTER JOIN table2
ON table1.person_uid = table2.person_uid
WHERE table2.person_uid is null
In diesem Fall fragen Sie für die Aufzeichnung, die keinen Datensatz in der zweiten Tabelle hat. Aber anders als dieser spezielle Fall, Sie ändern die links zu einem inneren Join, wenn Sie ein Feld in table2 in dem where-Klausel refence.
Wenn die Abfrage nicht schnell genug ist, ich an Ihrer Indizierung aussehen würde.
Alles, was jemand sagen Sie auf der Grundlage der Informationen, die Sie ist eine Vermutung zur Verfügung gestellt.
Schauen Sie sich den Ausführungsplan für die Abfrage. Wenn Sie keinen Grund für die Langsamkeit in dem Plan sehen, die den Plan hier posten.
http://download.oracle .com / docs / cd / B28359_01 / server.111 / b28274 / ex_plan.htm # PFGRF009
Haben Sie Indizes für person_uid
und period
für beide Tabellen zu den Themen?
Wenn nicht, fügen Sie sie und versuchen Sie es erneut.
Werfen Sie einen Blick auf dem Ausführungsplan und sieht, was die Abfrage tatsächlich tut.
Außerdem: Was sind die Datentypen der Felder? Sind sie gleich in beiden Tabellen? Eine implizite Umwandlung kann wirklich langsam Dinge nach unten.
Haben diese Tabellen Indizes für die Spalten Sie verbinden? Installieren von Oracle kostenlos sqldeveloper Produkt und verwenden Sie es eine „erklären“ auf dieser Abfrage zu tun und sehen, ob es sequenzielle Scans beiden Tabellen tut.
In einer linken verbinden Sie tabelle1 für jede einzelne Kombination des Abtastens werden würde (person_uid, Zeit), dann table2 für alle entsprechenden Datensätze dort zu suchen. Wenn table2 keinen geeigneten Index haben, kann dies auch das Scannen des gesamten dieser Tabelle betreffen.
Meine beste Vermutung, ohne einen Ausführungsplan zu sehen, ist, dass die erste Abfrage (die einzigen, die korrekt zu sein scheint) zu Tisch mit Scan table2 sowie tabelle1.
Wie 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
hier Die Hoffnung ist, dass Sie table2 Scan für jede einzelne Kombination von (person_uid, Zeitraum), aber die Verwendung von Indizes für tabelle1 machen. (Im Gegensatz zu scannen tabelle1 und die Nutzung von Indizes für table2, das, was ich aus der Abfrage zu erwarten.)
Wenn tabelle1 nicht entsprechenden Indizes haben, werden Sie jedoch sehr unwahrscheinlich, dass überhaupt keine Leistungsverbesserung sehen ...
Dems.
In einem der Updates der OP erklärt, dass er tatsächlich Ansichten nicht Tabellen abfragen. In diesem Fall könnte die Leistung gut direkt erhöht werden, indem die Tabellen abfragt er vor allem braucht, wenn die Ansichten zu vielen anderen Tabellen komplex und kommen sind, die er braucht keine Informationen enthalten, oder sie sind Ansichten, die Ansichten aufrufen.
ANSI-Join-Syntax eine sehr klare Unterscheidung zwischen bietet Joinbedingungen 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 „auf einer konstanten Verbindung“. Im wesentlichen wird die Filterbedingung verbinden äußeren zum Durchführen vor angewandt. So beseitigen Sie die Zeilen, die später hinzugefügt werden, als Teil der äußeren Rückseite verbinden. Es ist nicht unbedingt falsch, aber ist, dass die Abfrage, die Sie wirklich gefragt? Oft sind es die in Q2 gezeigten Ergebnisse, die erforderlich sind, wo der Filter angewendet wird, nachdem die (äußere) verbinden.
Es gibt auch eine Leistung Implikation auch für große Datenmengen. In vielen Fällen auf einem konstanten Verbindung hat intern vom Optimierungsprogramm gelöst werden, indem eine Seitenansicht zu schaffen, die in der Regel nur über eine verschachtelte Schleife optimiert werden können, kommt statt einem Hash-Join
Für Entwickler, die mit dem Oracle-Außen vertraut sind Join-Syntax, würde die Abfrage wahrscheinlich als
geschrieben wurdeSELECT 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.
Also zusammenfassend, ist es äußerst wichtig, das, dass Sie den Unterschied zwischen der JOIN-Klausel und der WHERE-Klausel zu verstehen, wenn das Schreiben ANSI-Outer-Joins.