Per "forzare" Oracle a utilizzare una scansione dell'indice, è sufficiente utilizzare un suggerimento di ottimizzazione INDEX_RS_ASC
. Per esempio:
CREATE TABLE mytable (a NUMBER NOT NULL, b NUMBER NOT NULL, c CHAR(10)) NOLOGGING;
INSERT /*+ APPEND */ INTO mytable(a,b,c)
SELECT level, mod(level,100)+1, 'a' FROM dual CONNECT BY level <= 1E6;
CREATE INDEX myindex_ba ON mytable(b, a);
EXECUTE dbms_stats.gather_table_stats(NULL,'mytable');
SELECT /*+ FULL(m) */ b FROM mytable m WHERE b=10; -- full table scan
SELECT /*+ INDEX_RS_ASC(m) */ b FROM mytable m WHERE b=10; -- index range scan
SELECT /*+ INDEX_FFS(m) */ b FROM mytable m WHERE b=10; -- index fast full scan
Se questo renderà la vostra richiesta in realtà correre più veloce dipende da molti fattori come la selettività del valore indicizzato o l'ordine fisico delle righe della tabella. Per esempio, se si modifica la query per WHERE b BETWEEN 10 AND <xxx>
, i seguenti costi appaiono nei piani di esecuzione sulla mia macchina:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 752
INDEX_RS_ASC 29 325 865 1943
INDEX_FFS 597 598 599 601
Se si modifica la query leggermente non solo per selezionare la colonna indicizzata b
, ma anche altri, colonne non indicizzate, i costi variano drasticamente:
b BETWEEN 10 AND 10 20 40 80
FULL 749 750 751 754
INDEX_RS_ASC 3352 40540 108215 243563
INDEX_FFS 3352 40540 108215 243563
fonte
2012-12-14 18:45:38
Dato che si tratta di un intervallo di scansione, mi chiedevo se le query "lente" si occupano di un intervallo più ampio (ad esempio un anno anziché una settimana). Nel qual caso ti aspetteresti che siano notevolmente più lenti. Ad un certo punto, quando l'intervallo diventa abbastanza grande, avrà senso passare dall'indice alla scansione completa. Che Oracle abbia indovinato correttamente quel punto è una questione diversa. –
Inoltre, se si sta eseguendo una scansione dell'indice completa e la tua query si sta aggiungendo a un'altra tabella, suppongo che non si unisca tramite un ciclo annidato: probabilmente sta passando a un hash o a unire join o unendo le tabelle in un ordine diverso. Se le query lente "dovrebbero" essere più rapide (ovvero non eseguono query IRL su una percentuale significativa della tabella), dovresti essere in grado di tornare alle scansioni di intervalli facendo riferimento a cicli annidati (con un suggerimento 'USE_NL' appropriato). –