lunes, 17 de febrero de 2014

Oracle RAC 12c sobre Oracle VM y VirtualBox usando Templates

OTN publicó hace unos días un hands-on lab How to Deploy a Four-Node Oracle RAC 12c Cluster in Minutes Using Oracle VM Templates, basado en una sesión del Oracle Open World 2013.
Es un artículo muy bueno, con todos los detalles para hacer la configuración e instalación, usando un equipo con 16gb de RAM para configurar 4 nodos virtuales con Oracle RAC 12c.

Pero sobre el final (y después de unas 3 hs de trabajo si se siguen las instrucciones) aclara: el objetivo del lab no es dejar corriendo el cluster porque no dan los recursos del servidor para hacerlo. Citando el texto original:
"Note: The goal of this lab is to show how to create a four-node cluster using Oracle VM with Flex Cluster 
and Oracle Flex ASM, not to actually run a four-node cluster. Because of the limited resources we have on the 
x86 machine, the build for this four-node cluster will not finish. By comparison, a similar deployment on a
 bare-metal/Oracle VM environment with adequate resources would take around 30 to 40 minutes."

Ya no parece tan interesante.
Pero con mínimos cambios se puede dejar corriendo un cluster de dos nodos. Ahora es más atractivo, aunque utiliza mucho hardware, pero es una buena alternativa por varios motivos:
  • el tiempo que lleva de deploy es menor a otras alternativas.
  • para familiarizarse con el uso de Oracle VM, templates de OVM, y Oracle RAC sin tener que instalar OVM en un servidor de pruebas.

Antes de contarles detalles sobre mi experiencia, un poco de background sobre las opciones para hacer deploys "rápidos" de máquinas virtuales con Oracle:
  • Oracle RAC está soportado en producción sobre varias tecnologías de virtualización, entre ellas Oracle VM (OVM), pero no VirtualBox.  OVM Server se debe instalar en el equipo que se use para virutalizar, lo que lo deja fuera notebooks o instalaciones de test que tienen otros propósitos y no hay nadie que se haga cargo de su administración (es más complejo administrar un equipo que usa OVM Server para correr virtuales que uno que usa Linux + VirtualBox)
  • Oracle tiene imágenes de máquinas virtuales OVM preinstaladas con todo lo necesario (VM Templates) para distintos propósitos, entre ellos la base de datos con la opción de RAC, para 11g y 12c. No hay templates para VirtualBox.
  • Siempre se puede crear desde cero las máquinas virtuales, instalar el sistema operativo, configurar storage, instalar Grid, Oracle y luego configurar todo. También hay guías muy buenas al respecto (como esta de Tim Hall - RAC 12c + OEL6 + virtualbox), pero es una tarea que lleva bastante más tiempo que solamente seguir la guía del lab.

Así que comparto mi experiencia usando un pc con AMD FX(tm)-8120 Eight-Core Processor de 1.4Ghz, 32Gb de RAM y openSUSE 12.3 x64


Primer intento

Siguiendo la guía al pie de la letra, el último paso que levanta las 4 VM de RAC falla con los siguientes mensajes, después de 4:45hs de haber comenzado el primer paso (sin contar el tiempo que lleva descargar los archivos que se necesitan).
tail -f /u01/racovm/buildcluster.log ERROR (node:rac2): Failed to run rootcrs.pl, status: 25 See log at: /u01/app/12.1.0/grid/cfgtoollogs/crsconfig/rootcrs_rac2_2014-02-15_11-32-40AM.log 2014-02-15 12:26:28:[girootcrslocal:Time :rac2] Completed with errors in 3230 seconds (0h:53m:50s), status: 25 INFO (node:rac0): All girootcrslocal operations completed on all (4) node(s) at: 12:27:22 2014-02-15 12:28:24:[girootcrs:Time :rac0] Completed with errors in 5497 seconds (1h:31m:37s), status: 3 2014-02-15 12:29:19:[creategrid:Time :rac0] Completed with errors in 5786 seconds (1h:36m:26s), status: 3 2014-02-15 12:29:43:[buildcluster:Time :rac0] Completed with errors in 6160 seconds (1h:42m:40s), status: 3

Segundo intento

Antes de descartar el uso de las 4 VM probé cambiar la configuración en VirtualBox del OVM server para que use 6 CPU en vez de las 2 que trae configuradas por defecto.
Usando la consola web de OVM Manager detuve las 4 VM, las borré y luego paré en VirtualBox OVM Server, cambié la configuración de CPUs, lo inicié y repetí los pasos desde el punto 11 (Clone Four Virtual Machines from the Template).

El resultado al levantar las VM fue el mismo: error. Aunque esta vez el servidor quedó bastante más cargado y casi no respondía
tail -f /u01/racovm/buildcluster.log ... ERROR (node:rac1): Failed to run rootcrs.pl, status: 25 See log at: /u01/app/12.1.0/grid/cfgtoollogs/crsconfig/rootcrs_rac1_2014-02-15_03-10-06PM.log 2014-02-15 16:17:24:[girootcrslocal:Time :rac1] Completed with errors in 4039 seconds (1h:07m:19s), status: 25 .... INFO (node:rac0): Waiting for all girootcrslocal operations to complete on all nodes (At 16:42:22, elapsed: 1h:28m:47s, 1 node(s) remaining, all background pid(s): 26984)...

Y esta es la carga del nodo0:
[root@rac0 ~]# uptime 18:32:08 up 4:11, 1 user, load average: 38.79, 36.94, 35.97


Intento final con dos nodos

Ahora sí para levantar un RAC con 2 nodos solamente, borré otra vez las 4 VM creadas usando la consola web de OVM Manager, y repetí los pasos desde el punto 11 (Clone Four Virtual Machines from the Template).

En el paso donde se indica crear el archivo netconfig12cRAC4node.ini, creé uno de nombre netconfig12cRAC2node.ini y dejé la configuración de dos nodos solamente (rac0 y rac1). El archivo params12c.ini no fue necesario crearlo nuevamente ni modificarlo.
El comando final (./deploycluster.py) usa el archivo de parámetros de 2 nodos, y esta vez el resultado es exitoso:

[root@ovm-mgr deploycluster]# ./deploycluster.py -u admin -M rac.? -N utils/netconfig12cRAC2node.ini -P utils/params12c.ini Oracle DB/RAC OneCommand (v2.0.3) for Oracle VM - deploy cluster - (c) 2011-2013 Oracle Corporation (com: 28700:v2.0.2, lib: 180072:v2.0.3, var: 1500:v2.0.3) - v2.4.3 - ovm-mgr.oow.com (x86_64) Invoked as root at Sun Feb 16 05:35:41 2014 (size: 45500, mtime: Tue Jul 30 16:55:37 2013) Using: ./deploycluster.py -u admin -M rac.? -N utils/netconfig12cRAC2node.ini -P utils/params12c.ini INFO: Login password to Oracle VM Manager not supplied on command line or environment (DEPLOYCLUSTER_MGR_PASSWORD), prompting... Password: INFO: Attempting to connect to Oracle VM Manager... INFO: Oracle VM Client (3.2.4.524) protocol (1.9) CONNECTED (tcp) to Oracle VM Manager (3.2.4.524) protocol (1.9) IP (192.168.56.3) UUID (0004fb0000010000285d60b0071f42ae) INFO: Inspecting /SoftOracle/deploycluster/utils/netconfig12cRAC2node.ini for number of nodes defined.... INFO: Detected 2 nodes in: /SoftOracle/deploycluster/utils/netconfig12cRAC2node.ini INFO: Located a total of (2) VMs; 2 VMs with a simple name of: ['rac.0', 'rac.1'] INFO: Detected (2) Hub nodes and (0) Leaf nodes in the Flex Cluster INFO: Detected a RAC deployment... INFO: Starting all (2) VMs... INFO: VM with a simple name of "rac.0" (Hub node) is in a Stopped state, attempting to start it....OK. INFO: VM with a simple name of "rac.1" (Hub node) is in a Stopped state, attempting to start it....OK. INFO: Verifying that all (2) VMs are in Running state and pass prerequisite checks... INFO: Detected Flex ASM enabled with a dedicated network adapter (eth2), all VMs will require a minimum of (3) Vnics... .. INFO: Skipped checking memory of VMs due to DEPLOYCLUSTER_SKIP_VM_MEMORY_CHECK=yes INFO: Detected that all (2) Hub node VMs specified on command line have (1) common shared disk between them (ASM_MIN_DISKS=1) INFO: The (2) VMs passed basic sanity checks and in Running state, sending cluster details as follows: netconfig.ini (Network setup): /SoftOracle/deploycluster/utils/netconfig12cRAC2node.ini params.ini (Overall build options): /SoftOracle/deploycluster/utils/params12c.ini buildcluster: yes INFO: Starting to send configuration details to all (2) VM(s)..... INFO: Sending to VM with a simple name of "rac.0" (Hub node)................. INFO: Sending to VM with a simple name of "rac.1" (Hub node)...... INFO: Configuration details sent to (2) VMs... Check log (default location /u01/racovm/buildcluster.log) on build VM (rac.0)... INFO: deploycluster.py completed successfully at 05:36:49 in 67.7 seconds (0h:01m:07s) Logfile at: /SoftOracle/deploycluster/deploycluster7.log


Y este es el log de la configuración exitosa de las VM:
tail -f /u01/racovm/buildcluster.log ... INFO (node:rac0): Running on: rac0 as oracle: export ORACLE_HOME=/u01/app/oracle/product/12.1.0/dbhome_1; /u01/app/oracle/product/12.1.0/dbhome_1/bin/srvctl status database -d ORCL Instance ORCL1 is running on node rac0 Instance ORCL2 is running on node rac1 INFO (node:rac0): Running on: rac0 as root: /u01/app/12.1.0/grid/bin/crsctl status resource -t -------------------------------------------------------------------------------- Name Target State Server State details -------------------------------------------------------------------------------- Local Resources -------------------------------------------------------------------------------- ora.ASMNET1LSNR_ASM.lsnr ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE ora.DATA.dg ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE ora.LISTENER.lsnr ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE ora.net1.network ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE ora.ons ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE ora.proxy_advm ONLINE ONLINE rac0 STABLE ONLINE ONLINE rac1 STABLE -------------------------------------------------------------------------------- Cluster Resources -------------------------------------------------------------------------------- ora.LISTENER_SCAN1.lsnr 1 ONLINE ONLINE rac0 STABLE ora.asm 1 ONLINE ONLINE rac0 STABLE 2 ONLINE ONLINE rac1 STABLE 3 OFFLINE OFFLINE STABLE ora.cvu 1 OFFLINE OFFLINE STABLE ora.gns 1 ONLINE ONLINE rac0 STABLE ora.gns.vip 1 ONLINE ONLINE rac0 STABLE ora.oc4j 1 OFFLINE OFFLINE STABLE ora.orcl.db 1 ONLINE ONLINE rac0 Open,STABLE 2 ONLINE ONLINE rac1 Open,STABLE ora.rac0.vip 1 ONLINE ONLINE rac0 STABLE ora.rac1.vip 1 ONLINE ONLINE rac1 STABLE ora.scan1.vip 1 ONLINE ONLINE rac0 STABLE -------------------------------------------------------------------------------- INFO (node:rac0): For an explanation on resources in OFFLINE state, see Note:1068835.1 2014-02-16 11:16:07:[clusterstate:Time :rac0] Completed successfully in 164 seconds (0h:02m:44s) 2014-02-16 11:16:13:[buildcluster:Done :rac0] Building 12c RAC Cluster 2014-02-16 11:16:16:[buildcluster:Time :rac0] Completed successfully in 9501 seconds (2h:38m:21s)


Finalmente, para validar que realmente está funcionando me conecto a una de las instancias del RAC:
server:/archivos/oracle # ssh oracle@192.168.56.10 oracle@192.168.56.10's password: [oracle@rac0 ~]$ echo $ORACLE_SID ORCL1 [oracle@rac0 ~]$ sqlplus / as sysdba SQL*Plus: Release 12.1.0.1.0 Production on Sun Feb 16 11:54:26 2014 Copyright (c) 1982, 2013, Oracle. All rights reserved. Connected to: Oracle Database 12c Enterprise Edition Release 12.1.0.1.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics and Real Application Testing options SQL> set lines 180 pages 180 SQL> col host_name for a10 SQL> select inst_id, version, instance_name, host_name, status 2 from gv$instance; INST_ID VERSION INSTANCE_NAME HOST_NAME STATUS ---------- ----------------- ---------------- ---------- ------------ 1 12.1.0.1.0 ORCL1 rac0 OPEN 2 12.1.0.1.0 ORCL2 rac1 OPEN

Espero les sea útil.

domingo, 26 de enero de 2014

Oracle SQL Developer 4.0 en OpenSuse y usando PostgreSQL!

Ayer estuve probando la nueva versión del utilitario Oracle SQL Developer que se liberó en diciembre (4.0.0.13), y entre muchas cosas nuevas (ver las 10 razones para usarlo, en inglés), encontré que se puede configurar una conexión a una base PostgreSQL, algo que me interesaba desde hace tiempo.

Si bien PostgreSQL no está dentro de las bases de terceros soportadas, ahora funciona, aunque algunas operaciones dan error (como por ejemplo ver los índices de una tabla), y no tiene las mismas funcionalidades que el utilitario nativo de PostgreSQL psql.

Pero es una buena señal, y con el tiempo se puede convertir en la herramienta necesaria para cualquier DBA que administra varios motores.  En mi caso uso habitualmente Oracle, MySQL y PostgreSQL, y ocasionalmente SQL Server, todas administrables desde SQL Developer. Esperemos que en breve se tenga la funcionalidad completa sobre bases PostgreSQL.

Para quienes les interese probarlo, les dejo el detalle de como instalarlo y hacerlo funcionar en OpenSuse 12.3 x64, conectando a una base PostgreSQL 9.2.4 que corre local (instalado del repositorio "openSUSE BuildService - Database").


1) Descargar software


2) Instalar

Dejé los archivos anteriores en el directorio /local/soft/oracle, y desde ahí lo instalé con root:

oraculo:/local/soft/oracle # rpm -Uvh sqldeveloper-4.0.0.13.80-1.noarch.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:sqldeveloper-4.0.0.13.80-1       ################################# [ 50%]
Cleaning up / removing...
   2:sqldeveloper-3.2.20.09.87-1      ################################# [100%]


Si se trata de usar SQL Developer sin instalar la JDK 1.7, da este error:

ncalero@oraculo:> sqldeveloper 

 Oracle SQL Developer
 Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.




Esto es porque OpenSuse incluye OpenJDK 1.7, que trae solo JRE (openjdk-1.7.0.6-8.28.3.x86_64):

oraculo:~ # rpm -qa | grep -i jdk
java-1_7_0-openjdk-1.7.0.6-8.28.3.x86_64

oraculo:~ # rpm -ql java-1_7_0-openjdk-1.7.0.6-8.28.3.x86_64
/usr/lib64/jvm-exports/java-1.7.0-openjdk
/usr/lib64/jvm-exports/java-1.7.0-openjdk-1.7.0
...
/usr/lib64/jvm/java-1.7.0-openjdk-1.7.0/jre
...

oraculo:~ # /usr/lib64/jvm/java-1.7.0-openjdk-1.7.0/jre/bin/java -version
java version "1.7.0_45"
OpenJDK Runtime Environment (IcedTea 2.4.3) (suse-8.28.3-x86_64)
OpenJDK 64-Bit Server VM (build 24.45-b08, mixed mode)


Así que se debe instalar la JDK 1.7:

oraculo:/local/soft/oracle # rpm -Uvh jdk-7u51-linux-x64.rpm
Preparing...                          ################################# [100%]
Updating / installing...
   1:jdk-2000:1.7.0_51-fcs            ################################# [100%]
Unpacking JAR files...
        rt.jar...
        jsse.jar...
        charsets.jar...
        tools.jar...
        localedata.jar...
        jfxrt.jar...


Podemos validar donde quedó instalado:

oraculo:/local/soft/oracle # rpm -ql jdk-2000:1.7.0_51-fcs
/etc
/etc/.java
/etc/.java/.systemPrefs
...
/usr/java/jdk1.7.0_51/bin
...

oraculo:/local/soft/oracle # /usr/java/jdk1.7.0_51/bin/java -version
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)


3) Configurar JDK en SQL Developer

Antes de ejecutar SQL Developer se debe modificar su configuración para que use el JDK recién instalado, agregando el path correcto en el archivo de configuración sqldeveloper.conf en la variable SetJavaHome. Lo modifiqué con un editor de texto (vi), dejando comentada la configuración original (../../jdk):

oraculo: # grep SetJavaHome /opt/sqldeveloper/sqldeveloper/bin/sqldeveloper.conf

#SetJavaHome ../../jdk
SetJavaHome /usr/java/jdk1.7.0_51


4) Agregar conexión a PostgreSQL

Ahora que está resuelta la instalación, abrimos SQL Developer:

ncalero@oraculo:~> sqldeveloper 

 Oracle SQL Developer
 Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.


Nos muestra la pantalla de inicio. En mi caso tenía una versión anterior (3.2) por lo que me migró algunas conexiones:



Ahora vamos a la configuración para agregar el driver de PostgreSQL. Esto se hace presionando Tools en el menú superior, y ahí eligiendo Preferences:



Ahora hay que elegir Database, y allí Third Party JDBC Drivers, donde se muestran los drivers ya configurados (en mi caso MySQL y SQL Server):



Con el botón "Add Entry ..." se debe elegir el archivo que bajamos antes, ubicado en /local/soft/oracle/postgresql-9.3-1100.jdbc41.jar.



Una vez elegido, presionamos el botón Select en este diálogo, y OK en el anterior para confirmar el cambio.

Para probar su funcionamiento creamos una nueva conexión. En este ejemplo usando el botón con el símbolo de más en el menú "Connections" de la izquierda:



Se abre el diáologo para ingresar los datos de la conexión, donde aparece una nueva pestaña "PostgreSQL":



En este ejemplo me voy a conectar a una base en el mismo equipo donde corre SQL Developer.
Si la base estuviera en otro servidor hay que revisar que se tenga permiso de acceso, tanto a nivel de IP (archivo pg_hba.conf) como en el usuario que se conecta a la base de datos.

Una vez que se ingresan los datos (hostname, port, username, password), se puede validar que la conexión funciona presionando el botón "Choose Database" para que nos muestre las bases a las que podemos conectarnos, y debemos elegir una de ellas para esta conexión:


Luego de elegida una base, podemos probar que la conexión funciona con el botón "Test" (aunque al funcionar la carga del combo de bases anteriores ya tenemos la pista de que va a funcionar). El resultado de este test se muestra en la parte inferior izquierda de esta ventana, donde dice Status:, como se ve en la siguiente captura marcado en rojo.


Al presionar Connect abrimos la conexión y podemos navegar en los objetos de la base tal como lo hacemos en Oracle, y ejecutar sentencias SQL.


Espero les sea útil.

martes, 31 de diciembre de 2013

Particiones, datos y optimización

Tenemos una tabla particionada y una consulta que anda lento porque la condición de where no incluye la columna de partición y usa columnas que no están indexadas.

¿Podemos hacer algo más que dar la recomendación obvia de crear un nuevo índice global?

Seguro!, por lo menos hacer estas dos revisiones rápidas.

Lo primero es ver si se usa la columna de particionamento en la condición del where.
Si se usa, la consulta solo leerá datos de esa partición (el optimizador aplica partition pruning), por lo tanto un nuevo índice podría ser útil siempre que las particiones tengan un volumen de datos que lo justifique (muchas particiones con pocos registros no se van a beneficiar de un nuevo índice).

Si no se usa la columna de particionamento en el where, todavía queda algo más a analizar: ¿el criterio de búsqueda tiene alguna correlación con el criterio de particionamiento? Esto es una relación funcional sobre los datos y que no podemos inferir a partir del texto de la consulta.

Podemos analizar los datos buscando este vínculo, y si se llega a confirmar podríamos hacer que la consulta sea más eficiente (recorra menos registros) modificandola, agregando una simple condición columna_partición=valor.

¿Cómo podemos hacer este análisis? Con la ayuda de la función DBMS_MVIEW.PMARKER, que dado un registro (rowid) retorna el nombre de la partición donde está almacenado.

Todo esto se puede ver mejor con un ejemplo. Usé Oracle 11.2.0.2 Enterprise Edition


Tenemos la tabla bigtbl_part particionada por rangos de la columna tipo, y un índice global:

12:40:43 PRU@ent11g> create table bigtbl_part (id, estado, tipo, clase, dato)
partition by range(tipo) (
     partition p0 values less than (1),
     partition p1 values less than (2),
     partition p2 values less than (3),
     partition p3 values less than (4),
     partition p4 values less than (5)
) as
select  rownum               id,
        floor(dbms_random.value(1,20)) estado,
        mod(rownum,5)        tipo,
        mod(rownum,10)       clase,
        'relleno'            dato
from  all_objects, all_objects

Table created.

Elapsed: 00:00:53.14

12:41:37 PRU@ent11g> create index idx1 on bigtbl_part(id) local;

Index created.

Elapsed: 00:00:15.90

12:42:20 PRU@ent11g> execute dbms_stats.gather_table_stats(user,'bigtbl_part')

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.99



Vemos cómo quedaron generados los datos. Nos vamos a enfocar en las clases y tipos:

12:42:40 PRU@ent11g>select count(*), clase from bigtbl_part group by clase order by clase;

  COUNT(*)      CLASE
---------- ----------
    100000          0
    100000          1
    100000          2
    100000          3
    100000          4
    100000          5
    100000          6
    100000          7
    100000          8
    100000          9

10 rows selected.


Los valores distintos de CLASE por cada partición (columna TIPO):

12:46:29 PRU@ent11g> select count(distinct clase), tipo
from bigtbl_part
group by tipo
order by tipo;

COUNT(DISTINCTCLASE)       TIPO
-------------------- ----------
                   2          0
                   2          1
                   2          2
                   2          3
                   2          4


Y cómo quedaron distribuidos los datos en cada partición:

12:47:40 PRU@ent11g> col partition_name for a10
12:47:41 PRU@ent11g> select partition_name, num_rows, high_value
from user_TAB_PARTITIONS
where table_name='BIGTBL_PART';

PARTITION_   NUM_ROWS HIGH_VALUE
---------- ---------- --------------------------------------------------------------------------------
P0             200000 1
P1             200000 2
P2             200000 3
P3             200000 4
P4             200000 5


Esta es la consulta que nos interesa mejorar:

  SELECT count(*)
  FROM bigtbl_part
  WHERE clase = :clase and estado = :estado;


Para fijar ideas usamos una combinación de valores cualquiera: buscamos registros de clase 3 y estado 15:

12:49:52 PRU@ent11g> var clase number;
12:49:52 PRU@ent11g> var estado number;

12:49:52 PRU@ent11g> exec :clase := 3;

PL/SQL procedure successfully completed.

12:49:52 PRU@ent11g> exec :estado := 15;

PL/SQL procedure successfully completed.

12:49:53 PRU@ent11g> set autotrace on explain

SELECT count(*)
FROM bigtbl_part
WHERE clase = :clase and estado = :estado;

  COUNT(*)
----------
      5265

Execution Plan
----------------------------------------------------------
Plan hash value: 1165574620

----------------------------------------------------------------------------------------------------
| Id  | Operation            | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |             |     1 |     6 |  1047   (2)| 00:00:13 |       |       |
|   1 |  SORT AGGREGATE      |             |     1 |     6 |            |          |       |       |
|   2 |   PARTITION RANGE ALL|             |  5263 | 31578 |  1047   (2)| 00:00:13 |     1 |     5 |
|*  3 |    TABLE ACCESS FULL | BIGTBL_PART |  5263 | 31578 |  1047   (2)| 00:00:13 |     1 |     5 |
----------------------------------------------------------------------------------------------------

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

   3 - filter("ESTADO"=TO_NUMBER(:ESTADO) AND "CLASE"=TO_NUMBER(:CLASE))


Vemos que para resolverla el optimizador tuvo que recorrer todas las particiones de la tabla, y cada una sin usar índice.

Podemos tener facilmente una idea de la cantidad máxima de registros que se necesitan analizar para responder esta consulta (peor caso):

12:53:04 PRU@ent11g>
select count(*), min(count(*)), max(count(*))
from BIGTBL_part
group by clase, estado;

  COUNT(*) MIN(COUNT(*)) MAX(COUNT(*))
---------- ------------- -------------
       190          5071          5500


Pero si queremos además saber en qué particiones están estos datos, no alcanza con ver la cantidad de registros que tiene cada partición (columna num_rows de DBA_TAB_PARTITIONS), ya que no estamos buscando dentro de una sola partición.
Tenemos que agregar a la consulta original el uso de la función dbms_mview.pmarker, y así ver si hay afinidad de los datos buscados (de la condición de agrupación) con las particiones.

Esta es una primera versión simple de la consulta, donde podemos ver los distintos valores de CLASES almacenados en cada partición:

12:54:12 PRU@ent11g>
select count(*)                      registros
      ,dbms_mview.pmarker(rowid)     data_object_id
      ,count(distinct clase)         clase_x_tipo
FROM bigtbl_part
group by dbms_mview.pmarker(rowid);

 REGISTROS DATA_OBJECT_ID CLASE_X_TIPO
---------- -------------- ------------
    200000          75537            2
    200000          75539            2
    200000          75540            2
    200000          75538            2
    200000          75536            2

Elapsed: 00:00:05.93
 


Agregando la condición original, podemos ver en qué particiones están los datos obtenidos:

12:56:51 PRU@ent11g>
select count(*)                      registros
      ,dbms_mview.pmarker(rowid)     data_object_id
FROM bigtbl_part
WHERE clase = :clase and estado = :estado
12:56:51   5  group by dbms_mview.pmarker(rowid);

 REGISTROS DATA_OBJECT_ID
---------- --------------
      5265          75539


Los 5265 registros que retorna la consulta se obtienen de la partición 75539.
Podemos ver el nombre de la partición consultando USER_OBJECTS:

12:58:17 PRU@ent11g>
select subobject_name
from user_objects
WHERE data_object_id=75539;

SUBOBJECT_NAME
------------------------------------------------------------------------------------------
P3


En resumen, aunque los datos se obtienen todos de la misma partición, la consulta recorre todas las particiones porque no conoce la relación entre los datos (clase y tipo).

En este ejemplo los datos se generaron de esta forma para ilustrar el caso donde se puede mejorar la consulta con la ayuda de los programadores de la aplicación, quienes pueden agregar una condición más al where sobre la columna TIPO con el valor correspondiente (ya que la relación entre los valores de estas columnas pueden ser conocidos), y así mejorar la peformance de la misma.
La consulta modificada quedaría así:

12:59:28 PRU@ent11g>
SELECT count(*)
FROM bigtbl_part
WHERE clase = :clase and estado = :estado and tipo = :tipo;

Plan hash value: 4104149755

-------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name        | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |
-------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |             |     1 |     9 |   211   (2)| 00:00:03 |       |       |
|   1 |  SORT AGGREGATE         |             |     1 |     9 |            |          |       |       |
|   2 |   PARTITION RANGE SINGLE|             |  1053 |  9477 |   211   (2)| 00:00:03 |   KEY |   KEY |
|*  3 |    TABLE ACCESS FULL    | BIGTBL_PART |  1053 |  9477 |   211   (2)| 00:00:03 |   KEY |   KEY |
-------------------------------------------------------------------------------------------------------

Si bien se mantiene el acceso sin índice, ahora es sobre la partición y no sobre todas las particiones.
Esto todavía puede mejorarse incluyendo un índice local por clase y estado si el volumen de las particiones lo amerita.
Si no se hubiera podido modificar la consulta, la recomendación clásica habría sido un índice global por clase y estado.

Otro tema relacionado a mejorar la performance de consultas sobre tablas particionadas, es la utilidad de tener índices que incluyan la columna de partición (conocidos como prefixed local index). Una buena discusión sobre el tema se puede encontrar en este thread de los foros de OTN

Espero les sea útil.

Un saludo y feliz comienzo de año!