2016-11-23 3 views
3

Ich habe eine Abfrage, die 17 Sekunden dauert, um auszuführen. Ich habe Indizes auf FIPS, STR_DT, END_DT angewendet, aber es dauert immer noch. Irgendwelche Vorschläge, wie ich die Leistung verbessern kann?Verbessern Join-Abfrage in Oracle

Meine Frage:

SELECT /*+ALL_ROWS*/ K_LF_SVA_VA.NEXTVAL VAL_REC_ID,  a.REC_ID, 
    b.VID, 
    1 VA_SEQ, 
    51 VA_VALUE_DATATYPE, 
    b.VALUE VAL_NUM, 
    SYSDATE CREATED_DATE, 
    SYSDATE UPDATED_DATE 
    FROM CTY_REC a JOIN FIPS_CONS b 
ON a.FIPS=b.FIPS AND a.STR_DT=b.STR_DT AND a.END_DT=b.END_DT; 


DESC CTY_REC; 

Name    Null Type   
------------------- ---- ------------- 
REC_ID     NUMBER(38)  
DATA_SOURCE_DATE   DATE   
STR_DT     DATE   
END_DT     DATE   
VID_RECSET_ID   NUMBER   
VID_VALSET_ID   NUMBER   
FIPS      VARCHAR2(255) 


DESC FIPS_CONS; 

Name   Null  Type   
------------- -------- ------------- 
STR_DT     DATE   
END_DT     DATE   
FIPS     VARCHAR2(255) 
VARIABLE    VARCHAR2(515) 
VALUE     NUMBER   
VID   NOT NULL NUMBER   

-Plan erklären:

Plan hash value: 919279614 

-------------------------------------------------------------- 
| Id | Operation   | Name       | 
-------------------------------------------------------------- 
| 0 | SELECT STATEMENT |        | 
| 1 | SEQUENCE   | K_VAL       | 
| 2 | HASH JOIN   |        | 
| 3 | TABLE ACCESS FULL| CTY_REC      | 
| 4 | TABLE ACCESS FULL| FIPS_CONS      | 
-------------------------------------------------------------- 

Ich habe Beschreibung der Tabellen hinzugefügt und Plan für meine Abfrage erklären.

+1

Wie viele Zeilen sind in den Tabellen? Wie viele Zeilen werden von der Abfrage projiziert? Welcher Anteil von Zeilen stimmt nicht mit Zeilen in der anderen Tabelle überein? Was ist der Cache-Wert für die Sequenz? –

+0

Können Sie den vollständigen Ausführungsplan anzeigen? Einschließlich der Zeilenschätzung und der Kosten Spalten (und vielleicht TmpSpc) –

Antwort

3

Auf dem Gesicht von ihm, und ohne Informationen über die Konfiguration der Sequenz, die Sie verwenden, die Anzahl der Zeilen in jeder Tabelle, und die Gesamtanzahl der Zeilen, die von der Abfrage projiziert wurden, ist es möglich, dass der Ausführungsplan, den Sie haben, der effizienteste ist, um alle Zeilen zurückzugeben.

Der Optimierer glaubt eindeutig, dass die Indizes nicht die Leistung verbessern, und dies ist oft wahrscheinlicher, wenn Sie für alle Zeilen optimieren, nicht für die ersten Zeilen. Indexbasierter Zugriff ist Einzelblock und eine Zeile zu einem Zeitpunkt, kann also inhärent langsamer sein als Vollblock-Vollscans pro Block.

Der Hash-Join, den Oracle verwendet, ist eine äußerst effiziente Möglichkeit zum Verknüpfen von Datensätzen. Wenn die Hash-Tabelle nicht so groß ist, dass sie auf die Festplatte übergeht, sind die Gesamtkosten nur geringfügig höher als bei vollständigen Scans der beiden Tabellen. Wir benötigen detailliertere Statistiken über die Ausführung, um feststellen zu können, ob die Hash-Tabelle auf die Festplatte ausgelaufen ist, und wenn dies der Fall ist, kann die Lösung nur die Speicherverwaltung ändern, nicht die Indizes.

Was auch Ihre SQL-Ausführung behindern könnte, ist diese Sequenz aufzurufen, wenn der Cache-Wert der Sequenz sehr niedrig ist und die Anzahl der Datensätze hoch ist. Weitere Informationen dazu erforderlich - wenn Sie für jede Zeile eine sequenzielle Kennung generieren müssen, können Sie ROWNUM verwenden.

+1

Ich mag diese Antwort. Sie haben Recht, vollständige Tabellenscans sind per se nicht schlecht. Sie sind manchmal der effizienteste Weg, um auf die Daten zuzugreifen. Und ja, ein Hash-Join ist eine großartige Technik, um zwei Tabellen zu verbinden. –

0

Dies ist im Grunde Ihre Frage:

SELECT . . . 
FROM CTY_REC a JOIN 
    FIPS_CONS b 
    ON a.FIPS = b.FIPS AND a.STR_DT = b.STR_DT AND a.END_DT = b.END_DT; 

Sie möchten einen zusammengesetzten Index für (FIPS, STR_DT, END_DT), vielleicht auf beiden Tabellen:

create index idx_cty_rec_3 on cty_rec(FIPS, STR_DT, END_DT); 
create index idx_fipx_con_3 on cty_rec(FIPS, STR_DT, END_DT); 

Eigentlich nur eine ist wahrscheinlich notwendig, aber beide gibt mit dem Optimierer mehr Möglichkeiten zur Verbesserung der Abfrage.

+0

habe ich bereits diese. – dang

0

Sie sollten diese beiden Indizes für die Tabelle zumindest:

  • CTY_REC (FIPS, STR_DT, END_DT)
  • FIPS_CONS (FIPS, STR_DT, END_DT)

die noch kann beschleunigt werden mit Indizes abdeckt statt:

  • CTY_REC (FIPS, STR_DT, END_DT, rec_id)
  • FIPS_CONS (FIPS, STR_DT, END_DT, VALUE, VID)
+0

Diese Indizes können größer als die Tabellen sein, wenn Sie die erforderlichen Zeilen- und Leerzeichen angeben. –

+0

@David Aldridge: Ja, manchmal werden Indizes groß, aber ich halte dies nicht für einen Grund, sie nicht zu verwenden. –

0

Wenn Sie das Optimierungsprogramm fahren wollen, die Indizes zu verwenden,
ersetzen /*+ all_rows */ mit /*+ first_rows */