sql >> Database >  >> RDS >> Oracle

Oracle - Indexgebruik met optionele parameters

De NVL truc zou moeten werken en indextoegang toestaan. In feite, NVL is over het algemeen de beste manier om dit te doen, en werkt meestal beter dan andere omstandigheden met betrekking tot CASE of OR . Ik heb de NVL . gebruikt truc vele malen en de eenvoudige testcase hieronder laat zien dat het een index kan gebruiken.

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

Uitvoeringsplan genereren

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

select * from table(dbms_xplan.display);

Uitvoeringsplan

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)

Dat plan is in het begin wat verwarrend. Maar het heeft het beste van twee werelden; de filterbewerking stelt Oracle in staat om tijdens runtime te beslissen om een ​​volledige tabelscan te gebruiken wanneer de bindvariabele null is (en alle rijen worden geretourneerd), en een index wanneer de bindvariabele niet null is (en slechts een paar rijen worden geretourneerd).

Dit alles betekent dat er waarschijnlijk iets raars aan de hand is in jouw specifieke geval. Mogelijk moet u een volledig reproduceerbare testcase voor ons posten om erachter te komen waarom een ​​index niet wordt gebruikt.




  1. Hoe gegevens uit tabellen op postgres te INTERSECTEREN

  2. Waarom kan ik afhankelijke kolommen niet uitsluiten van `GROUP BY` als ik aggregeer met een sleutel?

  3. codeigniter active record opvragen en opvragen zonder de LIMIT-clausule

  4. Som van Case Builder-expressie in QueryDSL