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é.