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

Oracle - Uso dell'indice con parametri facoltativi

Il NVL trucco dovrebbe funzionare e consentire l'accesso all'indice. Infatti, NVL è generalmente il modo migliore per farlo e di solito funziona meglio di altre condizioni che coinvolgono CASE o OR . Ho usato il NVL trucco molte volte e il semplice test case di seguito mostra che può utilizzare un indice.

Schema

create table xx_people(id_number number, a number, b number);

insert into xx_people
select level, level, level from dual connect by level <= 100000;

commit;

begin
    dbms_stats.gather_table_stats(user, 'xx_people');
end;
/

create index xx_people_idx1 on xx_people(id_number, -1);

Genera piano di esecuzione

explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);

select * from table(dbms_xplan.display);

Piano di esecuzione

Plan hash value: 3301250992

----------------------------------------------------------------------------------------------------------
| Id  | Operation                              | Name            | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                       |                 |   100K|  3808K|   106   (1)| 00:00:01 |
|   1 |  VIEW                                  | VW_ORE_67373E14 |   100K|  3808K|   106   (1)| 00:00:01 |
|   2 |   UNION-ALL                            |                 |       |       |            |          |
|*  3 |    FILTER                              |                 |       |       |            |          |
|   4 |     TABLE ACCESS BY INDEX ROWID BATCHED| XX_PEOPLE       |     1 |    15 |     3   (0)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN                  | XX_PEOPLE_IDX1  |     1 |       |     2   (0)| 00:00:01 |
|*  6 |    FILTER                              |                 |       |       |            |          |
|*  7 |     TABLE ACCESS FULL                  | XX_PEOPLE       |   100K|  1464K|   103   (1)| 00:00:01 |
----------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - filter(:P_ID_NUMBER IS NOT NULL)
   5 - access("ID_NUMBER"=:P_ID_NUMBER)
   6 - filter(:P_ID_NUMBER IS NULL)
   7 - filter("ID_NUMBER" IS NOT NULL)

Il piano è un po' confuso all'inizio. Ma ha il meglio di entrambi i mondi; l'operazione di filtro consente a Oracle di decidere in fase di esecuzione di utilizzare una scansione completa della tabella quando la variabile bind è nulla (e vengono restituite tutte le righe) e un indice quando la variabile bind non è nulla (e vengono restituite solo poche righe).

Tutto ciò significa che probabilmente sta succedendo qualcosa di strano nel tuo caso specifico. Potrebbe essere necessario pubblicare un test case completamente riproducibile per farci capire perché un indice non viene utilizzato.