NVL
trik seharusnya berfungsi dan memungkinkan akses indeks. Faktanya, NVL
umumnya cara terbaik untuk melakukan ini, dan biasanya bekerja lebih baik daripada kondisi lain yang melibatkan CASE
atau OR
. Saya telah menggunakan NVL
trik berkali-kali dan kasus uji sederhana di bawah ini menunjukkan bahwa ia dapat menggunakan indeks.
Skema
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);
Buat Rencana Eksekusi
explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);
select * from table(dbms_xplan.display);
Rencana Eksekusi
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)
Rencana itu agak membingungkan pada awalnya. Tapi itu punya yang terbaik dari kedua dunia; operasi filter memungkinkan Oracle untuk memutuskan pada saat run time untuk menggunakan pemindaian tabel lengkap ketika variabel bind adalah nol (dan semua baris dikembalikan), dan indeks ketika variabel bind tidak nol (dan hanya beberapa baris yang dikembalikan).
Ini semua berarti bahwa mungkin ada sesuatu yang aneh terjadi dalam kasus spesifik Anda. Anda mungkin perlu memposting kasus uji yang sepenuhnya dapat direproduksi agar kami mengetahui mengapa indeks tidak digunakan.