Oracle
 sql >> Database >  >> RDS >> Oracle

Strani cambiamenti di velocità con query sql

Per capire meglio cosa sta succedendo, prova questo:

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;

e poi:

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

Immagino che vedrai una riga che indica TABLE ACCESS FULL su claim_key.

Quindi prova:

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'));

e controlla per vedere quale indice utilizza (presumibilmente). Questo dovrebbe darti un'idea di cosa sta facendo il database, il che aiuta a capire perché lo sta facendo.

Ok, dati i tuoi piani di spiegazione, è un classico esempio di "gli indici non sono sempre buoni, le scansioni delle tabelle non sono sempre cattive".

L'INDEX SKIP SCAN è il punto in cui il database può provare a utilizzare un indice anche se la colonna iniziale dell'indice non viene nemmeno utilizzata. Fondamentalmente se il tuo indice assomigliava a questo (eccessivamente semplificato):

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

e la tua condizione era WHERE col2 ='X' la scansione di salto dell'indice dice di guardare attraverso ogni combinazione in COL1 per dove col2 ='X'. "Salta" i valori in col1 una volta trovata una corrispondenza (ad es. col1 =A, col2 =X) fino al punto in cui il valore cambia (col1 =B, quindi col1 =C, ecc.) e cerca più corrispondenze.

Il problema è che gli indici (generalmente!) funzionano in questo modo:1) trova il rowid successivo nell'indice in cui è stato trovato il valore2) vai al blocco della tabella con quel rowid (TABLE ACCESS BY INDEX ROWID)3) ripeti fino a quando non ci sono più corrispondenze si trovano.

(Per la scansione salta, comporterebbe anche il costo di scoprire dove si trova la prossima modifica del valore per le colonne iniziali.)

Tutto questo va bene per un piccolo numero di righe, ma soffre della legge dei rendimenti decrescenti; non è eccezionale quando hai un gran numero di righe. Questo perché deve leggere un blocco di indice, quindi un blocco di tabella, quindi un blocco di indice, un blocco di tabella (anche se il blocco di tabella è stato letto in precedenza).

La scansione completa della tabella "solleva" i dati grazie in parte a... letture multiblocco. Il database può leggere molti blocchi dal disco in una singola lettura e non legge lo stesso blocco più di una volta.

L'INDEX FAST FULL SCAN sta sostanzialmente trattando I_CLAIM_KEY_002 come una tabella. Tutto ciò di cui hai bisogno nella query può essere risolto dal solo indice; non è richiesto l'ACCESSO AL TAVOLO. (Suppongo che I_CLAIM_KEY_002 sia definito come clnt_id, dte_of_srvce e clnt_id o dte_of_srvce non sia nullable. Poiché ck.id dovrebbe essere un attributo non null, un conteggio su ck.id è uguale a un conteggio su ck.clnt_id.)

Quindi, per quanto riguarda la tua query iniziale, a meno che tu non voglia modificare i tuoi indici, prova questo:

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

che forzerà una scansione completa della tabella su claim_key (ck) e potresti vedere prestazioni simili agli altri due. (Verifica che questo sia il caso anteponendo alla query "explain plan set statement_id ='query_hint' for" ed eseguendo la query dbms_xplan prima di eseguirla.)

(Ora chiederai "voglio inserire sempre suggerimenti del genere"? Per favore non farlo. Questo è solo per un test. Questo è solo per verificare se un FTS è migliore dell'INDEX SKIP SCAN . Se lo è, allora devi scoprire perché. :)

Comunque... spero di aver reso snese... intendo dire sensato.