O
NVL
truque deve funcionar e permitir o acesso ao índice. Na verdade, NVL
geralmente é a melhor maneira de fazer isso e geralmente funciona melhor do que outras condições envolvendo CASE
ou OR
. Eu usei o NVL
trick muitas vezes e o caso de teste simples abaixo mostra que ele pode usar um índice. Esquema
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);
Gerar Plano de Execução
explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);
select * from table(dbms_xplan.display);
Plano de Execução
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)
Esse plano é um pouco confuso no início. Mas tem o melhor dos dois mundos; a operação de filtro permite que o Oracle decida em tempo de execução usar uma varredura completa da tabela quando a variável de ligação for nula (e todas as linhas forem retornadas) e um índice quando a variável de ligação não for nula (e apenas algumas linhas forem retornadas).
Isso tudo significa que provavelmente há algo estranho acontecendo no seu caso específico. Talvez seja necessário publicar um caso de teste totalmente reproduzível para descobrirmos por que um índice não é usado.