
La documentación de Oracle ofrece poca información sobre "best practices" relativas al partition pruning.
Es importante indicar en los filtros información que ayude al optimizador a determinar a qué particiones acceder. Por ejemplo, no es posible seleccionar particiones de tabla si se accede a través de un índice global, aunque todas las filas seleccionadas pertenezcan a una misma partición.
Además, existen dos tipos de pruning:
el estático, que se conoce directamente en el parse. Sucede, por ejemplo, cuando se filtra por una fecha concreta.
el dinámico, que es el que se resuelve en tiempo de ejecución. Un ejemplo podría ser cuando se utilizan operadores o funciones.
En base a esta teoría, un filtro sobre una columna clave de particionamiento (en este caso, FECHA), utilizando una función TO_DATE, debería ser suficiente para realizar partition pruning estático, pero no es así.
En un primer entorno Oracle11g, dos sentencias SELECT idénticas salvo el formato de fecha en el filtro de WHERE determinaba cardinalidades diferentes en planes de ejecución idénticos y, en tiempo de ejecución, se resolvían "row sources" diferentes.
Para estudiar este comportamiento, preparamos un laboratorio en Oracle12c para, además, determinar si se trataba de algo específico de la versión Oracle11g, o podía reproducirse en otras versiones.
Para preparar este laboratorio he usado la máquina virtual de Oracle Developers Day en versión 12c, que puedes descargarte en el enlace siguiente, y bajo un usuario nuevo llamado LABORATORIO creé una tabla particionada por fecha, cargué 31,5 millones de filas y recopilé estadísticas para tener un entorno lo más parecido al caso original.
No hay mucha información sobre las conversiones implícitas que el optimizador de Oracle realiza para evaluar filtros.
Aunque se recomienda usar los mismos formatos y restringir el uso de funciones sobre los valores de los campos, no hay una base clara de buenas prácticas sobre la implementación de filtros en las cláusulas WHERE.
Por un lado, usar una función en el campo que se evalúa invalida el uso de los índices sobre esa columna, pues estas funciones están alterando los valores y ya no pueden compararse con los usados en la ordenación del índice.
No obstante, incluso cuando los campos se dejan inalterados, es posible que Oracle realice conversiones internas que alteren los resultados de la fase de compilación y optimización del SQL.
¿Qué ocurre, por ejemplo, si se compara una fecha con otro literal de tipo timestamp (fecha con precisión de fracción de segundos y soporte de hora local) aún cuando el valor no tiene precisión de fracciones de segundo?
En el siguiente test hacemos la prueba con una tabla más grande, cargando fechas a partir de DBA_OBJECTS para tener un registro cada 10 segundos.
Así hacemos la comparativa de la conversión explícita TO_CHAR y TO_TIMESTAMP para evaluar cardinalidades.
El caso aplicado a índices basados en funciones es similar, con la complejidad que aporta el necesitar, en muchos casos, conocer la expresión exacta con la que se ha creado el índice basado en función.
Si la función expresada en la query no coincide exactamente con la expresión de función del índice, el optimizador no considerará su uso.
¿Conoces los efectos de utilizar máscaras de fecha en dos o cuatro dígitos de año? Según la teoría, debería ser transparente, sobre todo cuando las funciones se usan en la evaluación de literales, pero en la práctica no es así. Estos dos estudios analizan el comportamiento del optimizador de Oracle y desvelan trucos y posibles problemas de performance que tú puedes tener en tu entorno productivo.