¿Por qué los índices basados ​​en funciones que he creado reducen el costo pero no aparecen en el desglose del plan de explicación?

8

Perdón por los terribles nombres de columna / tabla, pero como esto es para un proyecto de trabajo, quería asegurarme de que estaba bien preguntar. Solo esperaba al menos saber por qué no veo que se utilicen mis índices funcionales, así que me sentí mejor al agregar estos índices en un entorno de producción.

La consulta está utilizando una vista que he creado que tiene varias columnas diferentes con una cláusula where que hace lo siguiente:

  ....
  AND e.sysid = NVL(wi.ALPHAid, -999)
  AND NVL(wi.ALPHAid,   -999)       <> -999
  AND NVL(wi.BRAVOid,   -999)        = -999
  AND NVL(wi.CHARLIEid, -999)        = -999
  ...

Tengo entendido que Oracle no puede usar índices si pasa la columna a través de una función y en su lugar necesita crear índices basados ​​en funciones. Entonces, antes de crear los índices, obtengo el siguiente costo en mi plan de explicación:

Valor hash del plan: 1233409744

-------------------------------------------------------------------------------------------------------------------
| Id  | Operation                        | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                 |                                |     1 |   223 |    56   (6)| 00:00:01 |
|   1 |  SORT ORDER BY                   |                                |     1 |   223 |    56   (6)| 00:00:01 |
|   2 |   HASH UNIQUE                    |                                |     1 |   223 |    55   (4)| 00:00:01 |
|   3 |    NESTED LOOPS                  |                                |     1 |   223 |    54   (2)| 00:00:01 |
|   4 |     NESTED LOOPS                 |                                |     1 |   136 |    49   (3)| 00:00:01 |
|   5 |      NESTED LOOPS OUTER          |                                |     1 |   112 |    48   (3)| 00:00:01 |
|*  6 |       HASH JOIN                  |                                |     1 |    87 |    48   (3)| 00:00:01 |
|*  7 |        HASH JOIN                 |                                |  3261 | 97830 |    29   (4)| 00:00:01 |
|   8 |         TABLE ACCESS FULL        | CHARLIE                        |  3261 | 39132 |    15   (0)| 00:00:01 |
|   9 |         TABLE ACCESS FULL        | BRAVO                          |  3261 | 58698 |    13   (0)| 00:00:01 |
|* 10 |        TABLE ACCESS FULL         | ALPHA                          |  3291 |   183K|    19   (0)| 00:00:01 |
|  11 |       TABLE ACCESS BY INDEX ROWID| LOCATION                       |     1 |    25 |     0   (0)| 00:00:01 |
|* 12 |        INDEX RANGE SCAN          | ALPHA_SRVDELLOC_IN1            |     1 |       |     0   (0)| 00:00:01 |
|  13 |      TABLE ACCESS BY INDEX ROWID | DELTA                          |     1 |    24 |     1   (0)| 00:00:01 |
|* 14 |       INDEX UNIQUE SCAN          | DELTA_PK                       |     1 |       |     0   (0)| 00:00:01 |
|* 15 |     TABLE ACCESS BY INDEX ROWID  | ITEM                           |     1 |    87 |     5   (0)| 00:00:01 |
|* 16 |      INDEX SKIP SCAN             | IDX_ITM                        |     1 |       |     4   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   6 - access("PR"."SYSID"="E"."BRAVOID" AND "E"."CHARLIEID"="MR"."SYSID")
   7 - access("PR"."SYSID"="MR"."BRAVOID")
  10 - filter("E"."SYSID"<>(-999))
  12 - access("E"."SYSID"="SD"."ALPHAID"(+))
       filter("SD"."ALPHAID"(+)<>(-999))
  14 - access("PR"."DELTAID"="P"."SYSID")
  15 - filter(("WI"."TYPE"='XZ' OR "WI"."TYPE"='Z' OR 
              "WI"."TYPE"='X') AND "WI"."DELINQUENT"='F' AND ("WI"."ACTIVE"='F' OR 
              NVL("WI"."LOCKEDBY",(-999))<>(-999)) AND "WI"."SUSPENDED"='F' AND ("WI"."LOCKEDBY" 
              IS NULL OR "WI"."LOCKEDBY"=12))
  16 - access("WI"."CODE"='MISSING' AND "WI"."TERMINATED"='F')
       filter("WI"."TERMINATED"='F' AND NVL("WI"."ALPHAID",(-999))<>(-999) AND 
              NVL("WI"."BRAVOID",(-999))=(-999) AND NVL("WI"."CHARLIEID",(-999))=(-999) AND 
              "E"."SYSID"=NVL("WI"."ALPHAID",(-999)))

Después de crear los siguientes índices:

CREATE INDEX "IDX_WFITEM_NVL_BRAVOID" ON ITEM (NVL(BRAVOID, -999));
CREATE INDEX "IDX_WFITEM_NVL_CHARLIEID" ON ITEM (NVL(CHARLIEID, -999));
CREATE INDEX "IDX_WFITEM_NVL_ALPHAID" ON ITEM (NVL(ALPHAID, -999));

Me sale el siguiente plan:

Valor hash del plan: 1066773928

----------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                           | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                                |     1 |   232 |    12  (17)| 00:00:01 |
|   1 |  SORT ORDER BY                      |                                |     1 |   232 |    12  (17)| 00:00:01 |
|   2 |   HASH UNIQUE                       |                                |     1 |   232 |    11  (10)| 00:00:01 |
|   3 |    NESTED LOOPS                     |                                |       |       |            |          |
|   4 |     NESTED LOOPS                    |                                |     1 |   232 |    10   (0)| 00:00:01 |
|   5 |      NESTED LOOPS                   |                                |     1 |   208 |     9   (0)| 00:00:01 |
|   6 |       NESTED LOOPS                  |                                |     1 |   190 |     8   (0)| 00:00:01 |
|   7 |        NESTED LOOPS OUTER           |                                |     1 |   178 |     7   (0)| 00:00:01 |
|   8 |         NESTED LOOPS                |                                |     1 |   153 |     7   (0)| 00:00:01 |
|*  9 |          TABLE ACCESS BY INDEX ROWID| ITEM                           |     1 |    96 |     6   (0)| 00:00:01 |
|* 10 |           INDEX SKIP SCAN           | IDX_ITM                        |     1 |       |     5   (0)| 00:00:01 |
|  11 |          TABLE ACCESS BY INDEX ROWID| ALPHA                          |     1 |    57 |     1   (0)| 00:00:01 |
|* 12 |           INDEX UNIQUE SCAN         | ALPHA_PK                       |     1 |       |     0   (0)| 00:00:01 |
|  13 |         TABLE ACCESS BY INDEX ROWID | LOCATION                       |     1 |    25 |     0   (0)| 00:00:01 |
|* 14 |          INDEX RANGE SCAN           | ALPHA_SRVDELLOC_IN1            |     1 |       |     0   (0)| 00:00:01 |
|  15 |        TABLE ACCESS BY INDEX ROWID  | CHARLIE                        |     1 |    12 |     1   (0)| 00:00:01 |
|* 16 |         INDEX UNIQUE SCAN           | CHARLIE_PK                     |     1 |       |     0   (0)| 00:00:01 |
|  17 |       TABLE ACCESS BY INDEX ROWID   | BRAVO                          |     1 |    18 |     1   (0)| 00:00:01 |
|* 18 |        INDEX UNIQUE SCAN            | BRAVO_PK                       |     1 |       |     0   (0)| 00:00:01 |
|* 19 |      INDEX UNIQUE SCAN              | DELTA_PK                       |     1 |       |     0   (0)| 00:00:01 |
|  20 |     TABLE ACCESS BY INDEX ROWID     | DELTA                          |     1 |    24 |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   9 - filter(("WI"."TYPE"='XZ' OR "WI"."TYPE"='Z' OR 
              "WI"."TYPE"='X') AND "WI"."DELINQUENT"='F' AND ("WI"."ACTIVE"='F' OR 
              NVL("WI"."LOCKEDBY",(-999))<>(-999)) AND "WI"."SUSPENDED"='F' AND ("WI"."LOCKEDBY" IS 
              NULL OR "WI"."LOCKEDBY"=12))
  10 - access("WI"."CODE"='MISSING' AND "WI"."TERMINATED"='F')
       filter("WI"."TERMINATED"='F' AND NVL("BRAVOID",(-999))=(-999) AND 
              NVL("CHARLIEID",(-999))=(-999) AND NVL("ALPHAID",(-999))<>(-999))
  12 - access("E"."SYSID"=NVL("ALPHAID",(-999)))
       filter("E"."SYSID"<>(-999))
  14 - access("E"."SYSID"="SD"."ALPHAID"(+))
       filter("SD"."ALPHAID"(+)<>(-999))
  16 - access("E"."CHARLIEID"="MR"."SYSID")
  18 - access("PR"."SYSID"="MR"."BRAVOID")
       filter("PR"."SYSID"="E"."BRAVOID")
  19 - access("PR"."DELTAID"="P"."SYSID")

Como puede ver, el costo se reduce considerablemente, pero ¿por qué no veo los índices recién creados?

Esperaba verlos usados ​​en el plan de explicación, pero en cambio lo veo usando el índice de clave primaria apropiado y el índice "IDX_ITM".

Avíseme si necesita más información y veré si puedo proporcionarla.

Rapida
fuente
1
¿Aún obtiene el "nuevo" plan si elimina los índices? ¿Recalculó alguna estadística?
Mat
Vuelve al plan anterior si los descarto y el nuevo plan aparece si los agrego nuevamente. Lo ha hecho consistentemente a través de múltiples intentos de descubrir qué está sucediendo. He usado OEM para recopilar estadísticas después de soltar los índices y después de volver a agregarlos. También verifiqué el plan de ejecución que muestra OEM después de ejecutar la consulta y aún muestra el costo reducido pero no hay signos de mis nuevos índices.
Rapida
¿Encontraste la razón? @Rapida
Vimal Bhaskar

Respuestas:

1

De la sección Notas sobre índices basados ​​en funciones de la documentación del usuario para CREATE INDEX:

  • Cuando posteriormente consulta una tabla que usa un índice basado en funciones, Oracle Database no usará el índice a menos que la consulta filtre valores nulos . Sin embargo, Oracle Database utilizará un índice basado en funciones en una consulta, incluso si las columnas especificadas en la cláusula WHERE están en un orden diferente al de la columna_expresión que definió el índice basado en funciones.

Por lo tanto, puede intentar agregar las NOT NULLcondiciones adecuadas a su consulta.

Centinela
fuente