sql >> Base de Datos >  >> RDS >> Oracle

Oracle:uso de índices con parámetros opcionales

El NVL el truco debería funcionar y permitir el acceso al índice. De hecho, NVL es generalmente la mejor manera de hacer esto, y generalmente funciona mejor que otras condiciones que involucran CASE o OR . He usado el NVL truco muchas veces y el caso de prueba simple a continuación muestra que puede usar un índice.

Esquema

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

Generar Plan de Ejecución

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

select * from table(dbms_xplan.display);

Plan de Ejecución

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)

Ese plan es un poco confuso al principio. Pero tiene lo mejor de ambos mundos; la operación de filtro permite que Oracle decida en tiempo de ejecución usar un escaneo completo de la tabla cuando la variable de vinculación es nula (y se devuelven todas las filas), y un índice cuando la variable de vinculación no es nula (y solo se devuelven unas pocas filas).

Todo esto significa que probablemente esté sucediendo algo extraño en su caso específico. Es posible que deba publicar un caso de prueba completamente reproducible para que descubramos por qué no se usa un índice.