NVL
sztuczka powinna działać i umożliwiać dostęp do indeksu. W rzeczywistości NVL
jest generalnie najlepszym sposobem na zrobienie tego i zwykle działa lepiej niż inne warunki dotyczące CASE
lub OR
. Użyłem NVL
wiele razy, a prosty przypadek testowy poniżej pokazuje, że może używać indeksu.
Schemat
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);
Wygeneruj plan wykonania
explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);
select * from table(dbms_xplan.display);
Plan wykonania
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)
Ten plan jest początkowo trochę zagmatwany. Ale ma to, co najlepsze z obu światów; Operacja filtrowania pozwala Oracle na podjęcie w czasie wykonywania decyzji o użyciu pełnego skanowania tabeli, gdy zmienna wiązania ma wartość NULL (i zwracane są wszystkie wiersze) oraz indeks, gdy zmienna wiązania nie ma wartości NULL (i zwracanych jest tylko kilka wierszy).
To wszystko oznacza, że prawdopodobnie dzieje się coś dziwnego w twoim konkretnym przypadku. Może być konieczne opublikowanie w pełni odtwarzalnego przypadku testowego, abyśmy mogli dowiedzieć się, dlaczego indeks nie jest używany.