NVL
トリックが機能し、インデックスアクセスを許可する必要があります。実際、NVL
これを行うには通常、これが最善の方法であり、通常、CASE
を含む他の条件よりもうまく機能します。 またはOR
。 NVL
を使用しました 何度もトリックを行い、以下の簡単なテストケースは、インデックスを使用できることを示しています。
スキーム
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);
実行計画の生成
explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);
select * from table(dbms_xplan.display);
実行計画
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)
その計画は最初は少し混乱します。しかし、それは両方の長所を持っています。フィルタ操作により、Oracleは、実行時に、バインド変数がnullの場合(およびすべての行が返される場合)に全表スキャンを使用し、バインド変数がnullでない場合(および少数の行のみが返される場合)にインデックスを使用することを決定できます。
これはすべて、あなたの特定のケースでおそらく何か奇妙なことが起こっていることを意味します。インデックスが使用されない理由を理解するために、完全に再現可能なテストケースを投稿する必要があるかもしれません。