Oracle
 sql >> Base de données >  >> RDS >> Oracle

Oracle - Utilisation de l'index avec des paramètres facultatifs

Le NVL l'astuce devrait fonctionner et permettre l'accès à l'index. En fait, NVL est généralement la meilleure façon de le faire, et fonctionne généralement mieux que d'autres conditions impliquant CASE ou OR . J'ai utilisé le NVL astuce plusieurs fois et le cas de test simple ci-dessous montre qu'il peut utiliser un index.

Schéma

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

Générer un plan d'exécution

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

select * from table(dbms_xplan.display);

Plan d'exécution

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)

Ce plan est un peu déroutant au début. Mais il a le meilleur des deux mondes; l'opération de filtrage permet à Oracle de décider au moment de l'exécution d'utiliser une analyse complète de la table lorsque la variable de liaison est nulle (et que toutes les lignes sont renvoyées), et un index lorsque la variable de liaison n'est pas nulle (et que seules quelques lignes sont renvoyées).

Tout cela signifie qu'il se passe probablement quelque chose de bizarre dans votre cas spécifique. Vous devrez peut-être publier un cas de test entièrement reproductible pour que nous comprenions pourquoi un index n'est pas utilisé.