Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Oracle - Indexverwendung mit optionalen Parametern

Die NVL Trick sollte funktionieren und Indexzugriff erlauben. Genau genommen NVL ist im Allgemeinen der beste Weg, dies zu tun, und funktioniert normalerweise besser als andere Bedingungen mit CASE oder OR . Ich habe die NVL verwendet Trick viele Male und der einfache Testfall unten zeigt, dass es einen Index verwenden kann.

Schema

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);

Ausführungsplan erstellen

explain plan for
select *
from xx_people
where id_number = nvl(:p_id_number, id_number);

select * from table(dbms_xplan.display);

Ausführungsplan

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)

Dieser Plan ist zunächst etwas verwirrend. Aber es hat das Beste aus beiden Welten; Die Filteroperation ermöglicht es Oracle, zur Laufzeit zu entscheiden, einen vollständigen Tabellenscan zu verwenden, wenn die Bind-Variable null ist (und alle Zeilen zurückgegeben werden), und einen Index, wenn die Bind-Variable nicht null ist (und nur wenige Zeilen zurückgegeben werden).

Das alles bedeutet, dass in Ihrem speziellen Fall wahrscheinlich etwas Seltsames vor sich geht. Möglicherweise müssen Sie einen vollständig reproduzierbaren Testfall posten, damit wir herausfinden können, warum kein Index verwendet wird.