Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Seltsame Geschwindigkeitsänderungen bei SQL-Abfragen

Versuchen Sie Folgendes, um besser zu verstehen, was vor sich geht:

explain plan set statement_id = 'query1' for
SELECT  count(ck.id)
FROM    claim_key ck
WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
     AND ck.clm_type = 5
     AND ck.prgrm_id = 1;

und dann:

select *
from table(dbms_xplan.display(statement_id=>'query1'));

Ich schätze, Sie werden eine Zeile sehen, die TABLE ACCESS FULL auf Claim_key anzeigt.

Versuchen Sie dann:

explain plan set statement_id = 'query2' for
SELECT  count(ck.id)
FROM    claim_key ck
WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
     AND ck.clm_type = 5;

select *
from table(dbms_xplan.display(statement_id=>'query2'));

und überprüfen Sie, welchen Index es (vermutlich) verwendet. Das sollte Ihnen eine Vorstellung davon geben, was die Datenbank tut, was hilft herauszufinden, warum es tut es.

Ok, angesichts Ihrer Erklärungspläne ist dies ein klassisches Beispiel für "Indizes sind nicht immer gut, Tabellenscans sind nicht immer schlecht".

Beim INDEX SKIP SCAN kann die Datenbank versuchen, einen Index zu verwenden, obwohl die führende Spalte des Index nicht einmal verwendet wird. Grundsätzlich, wenn Ihr Index so aussah (zu stark vereinfacht):

COL1   COL2   ROWID
A      X      1        <--
A      Y      2
A      Z      3
B      X      4        <--
B      Y      5
B      Z      6 

und Ihre Bedingung war WHERE col2 ='X', der Index-Skip-Scan sagt, dass Sie jede Kombination in COL1 durchsehen, um zu sehen, wo col2 ='X' ist. Es "überspringt" die Werte in Spalte1, sobald es eine Übereinstimmung gefunden hat (z. B. Spalte1 =A, Spalte2 =X), bis zu der Stelle, an der sich der Wert ändert (Spalte1 =B, dann Spalte1 =C usw.) und sucht nach weiteren Übereinstimmungen.

Der Haken ist, dass Indizes (im Allgemeinen!) so funktionieren:1) Finde die nächste Zeilen-ID im Index, wo der Wert gefunden wurde. 2) Gehe zum Tabellenblock mit dieser Zeilen-ID (TABLE ACCESS BY INDEX ROWID). gefunden werden.

(Für den Skip-Scan würden auch die Kosten für das Herausfinden entstehen, wo die nächste Wertänderung für die führenden Spalten ist.)

Das ist alles gut und schön für eine kleine Anzahl von Reihen, leidet aber unter dem Gesetz des abnehmenden Ertrags; Es ist nicht so toll, wenn Sie eine große Anzahl von Zeilen haben. Das liegt daran, dass es einen Indexblock lesen muss, dann einen Tabellenblock, dann einen Indexblock, einen Tabellenblock (auch wenn der Tabellenblock zuvor gelesen wurde.)

Der vollständige Tabellenscan "pflügt" nur durch die Daten, teilweise dank ... Multiblock-Lesevorgängen. Die Datenbank kann viele Blöcke in einem einzigen Lesevorgang von der Festplatte lesen und liest denselben Block nicht mehr als einmal.

Der INDEX FAST FULL SCAN behandelt I_CLAIM_KEY_002 grundsätzlich als Tabelle. Alles, was Sie in der Abfrage benötigen, kann allein durch den Index beantwortet werden; es ist kein TABELLENZUGRIFF erforderlich. (Ich vermute, I_CLAIM_KEY_002 ist definiert als clnt_id, dte_of_srvce und entweder clnt_id oder dte_of_srvce ist nicht nullable. Da ck.id ein Nicht-Null-Attribut sein sollte, ist eine Zählung auf ck.id dasselbe wie eine Zählung auf ck.clnt_id.)

Was Ihre erste Abfrage betrifft, versuchen Sie Folgendes, es sei denn, Sie möchten Ihre Indizes neu ausrichten:

SELECT  /*+ FULL(ck) */ count(ck.id)
FROM    claim_key ck
WHERE   (ck.dte_of_srvce > (SYSDATE - INTERVAL '30' DAY))
     AND ck.clm_type = 5
     AND ck.prgrm_id = 1

Dadurch wird ein vollständiger Tabellenscan auf Claim_key (ck) erzwungen, und Sie könnten eine ähnliche Leistung wie die anderen beiden sehen. (Überprüfen Sie, ob dies der Fall ist, indem Sie der Abfrage zuerst "explain plan set statement_id ='query_hint' for" voranstellen und die dbms_xplan-Abfrage ausführen, bevor Sie sie ausführen.)

(Jetzt werden Sie fragen:"Möchte ich solche Hinweise die ganze Zeit einfügen?"? Bitte nicht. Dies ist nur für einen Test. Dies dient nur dazu, um zu sehen, ob ein FTS besser ist als der INDEX SKIP SCAN . Wenn ja, dann müssen Sie herausfinden, warum. :)

Wie auch immer ... Ich hoffe, das hat Sinn gemacht ... Ich meine, Sinn.