Cómo actualizar, exportar e importar estadísticas en Oracle Database 19c y 21c

Las estadísticas del optimizador son esenciales para el rendimiento de una base de datos Oracle. El Cost-Based Optimizer, conocido como CBO, utiliza esta información para estimar la cantidad de filas, el costo de las operaciones y el método más eficiente para ejecutar una sentencia SQL.

Cuando las estadísticas están ausentes, desactualizadas o no representan correctamente los datos, Oracle puede seleccionar planes de ejecución deficientes. Esto puede provocar full table scans innecesarios, joins costosos, consumo elevado de CPU, exceso de lecturas lógicas y tiempos de respuesta impredecibles.

En esta guía aprenderemos a:

  • Identificar estadísticas faltantes o desactualizadas.
  • Actualizar estadísticas de tablas, índices, esquemas y bases completas.
  • Gestionar estadísticas de tablas particionadas.
  • Utilizar estadísticas pendientes.
  • Bloquear y desbloquear estadísticas.
  • Restaurar una versión anterior.
  • Exportar e importar estadísticas entre ambientes.
  • Validar el resultado sin afectar la operación.

Los ejemplos están orientados a Oracle Database 19c y 21c.

Actualizar estadísticas no modifica los datos de negocio. Sin embargo, puede cambiar los planes de ejecución utilizados por el optimizador y, por lo tanto, afectar el rendimiento de las aplicaciones.

1. ¿Qué son las estadísticas del optimizador?

Las estadísticas describen las características de los objetos y de los datos almacenados.

Para una tabla pueden incluir:

  • Número de filas.
  • Número de bloques.
  • Tamaño promedio de las filas.
  • Fecha del último análisis.
  • Porcentaje utilizado para obtener la muestra.
  • Estadísticas de columnas.
  • Número de valores distintos.
  • Cantidad de valores nulos.
  • Valores mínimo y máximo.
  • Histogramas.
  • Estadísticas de índices.
  • Factor de clustering.
  • Profundidad del índice.
  • Número de bloques hoja.
  • Estadísticas de particiones y subparticiones.
  • Estadísticas extendidas sobre grupos de columnas o expresiones.

Oracle utiliza estas propiedades junto con los parámetros del optimizador y las estadísticas del sistema para estimar la cardinalidad de cada operación.

El paquete recomendado para administrarlas es DBMS_STATS. Oracle indica que este paquete permite recopilar, consultar y modificar estadísticas utilizadas por el optimizador. La base normalmente ejecuta una recopilación automática, por lo que los procedimientos manuales deben reservarse para situaciones controladas o especializadas. Consulta la documentación oficial de DBMS_STATS.

2. ¿Cuándo deben actualizarse?

Oracle recopila estadísticas automáticamente durante las ventanas de mantenimiento, pero pueden ser necesarias ejecuciones adicionales cuando:

  • Se realiza una carga masiva.
  • Se migra información.
  • Se agrega o elimina una gran cantidad de filas.
  • Se crea un índice.
  • Se trunca o reconstruye una tabla.
  • Se intercambia una partición.
  • Cambia significativamente la distribución de una columna.
  • Se clona una base de datos.
  • Se importa un esquema mediante Data Pump.
  • Se ejecuta un deployment que modifica objetos.
  • Aparecen planes de ejecución inesperados.
  • Una tabla nueva comienza a recibir tráfico antes de la ventana automática.
  • Un proceso batch debe utilizar inmediatamente los nuevos datos.
  • Las estadísticas automáticas no pueden terminar dentro de la ventana.

No deben recopilarse estadísticas de toda la base como reacción automática ante cualquier lentitud. Primero debe comprobarse que realmente estén ausentes, obsoletas o sean responsables de un cambio de plan.

3. Consultar cuándo fueron actualizadas

Para revisar las estadísticas de una tabla:

SELECT owner,
       table_name,
       num_rows,
       blocks,
       avg_row_len,
       sample_size,
       last_analyzed,
       stale_stats,
       stattype_locked
FROM dba_tab_statistics
WHERE owner = 'APPUSER'
  AND table_name = 'ORDERS';

Para identificar objetos con estadísticas faltantes o posiblemente obsoletas:

SELECT owner,
       table_name,
       partition_name,
       num_rows,
       last_analyzed,
       stale_stats,
       stattype_locked
FROM dba_tab_statistics
WHERE owner = 'APPUSER'
  AND (last_analyzed IS NULL OR stale_stats = 'YES')
ORDER BY table_name, partition_name;

STALE_STATS = 'YES' generalmente indica que el volumen de modificaciones superó el porcentaje configurado mediante la preferencia STALE_PERCENT.

Oracle mantiene información sobre inserciones, actualizaciones y eliminaciones. Para llevarla al diccionario antes de efectuar una validación manual puede utilizarse:

EXEC DBMS_STATS.FLUSH_DATABASE_MONITORING_INFO;

Después:

SELECT table_owner,
       table_name,
       inserts,
       updates,
       deletes,
       timestamp,
       truncated
FROM dba_tab_modifications
WHERE table_owner = 'APPUSER'
ORDER BY timestamp DESC;

No conviene ejecutar el FLUSH_DATABASE_MONITORING_INFO continuamente en scripts de monitoreo. Normalmente Oracle actualiza esta información de manera automática.

4. Consultar las preferencias de recopilación

Antes de lanzar DBMS_STATS, revisa las preferencias efectivas del objeto:

SELECT DBMS_STATS.GET_PREFS(
           pname   => 'ESTIMATE_PERCENT',
           ownname => 'APPUSER',
           tabname => 'ORDERS'
       ) AS estimate_percent
FROM dual;

Puedes consultar otras preferencias:

SELECT DBMS_STATS.GET_PREFS(
           pname   => 'METHOD_OPT',
           ownname => 'APPUSER',
           tabname => 'ORDERS'
       ) AS method_opt
FROM dual;
SELECT DBMS_STATS.GET_PREFS(
           pname   => 'STALE_PERCENT',
           ownname => 'APPUSER',
           tabname => 'ORDERS'
       ) AS stale_percent
FROM dual;

Preferencias importantes:

  • ESTIMATE_PERCENT
  • METHOD_OPT
  • DEGREE
  • CASCADE
  • NO_INVALIDATE
  • GRANULARITY
  • INCREMENTAL
  • INCREMENTAL_STALENESS
  • STALE_PERCENT
  • PUBLISH

5. Actualizar las estadísticas de una tabla

Ejemplo recomendado:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname          => 'APPUSER',
        tabname          => 'ORDERS',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        degree           => DBMS_STATS.AUTO_DEGREE,
        cascade          => DBMS_STATS.AUTO_CASCADE,
        no_invalidate    => DBMS_STATS.AUTO_INVALIDATE
    );
END;
/

Significado de los parámetros

ParámetroFunción
ownnamePropietario de la tabla
tabnameNombre de la tabla
estimate_percentPorcentaje de datos analizados
method_optControla estadísticas de columnas e histogramas
degreeGrado de paralelismo
cascadeIncluye estadísticas de índices
no_invalidateControla la invalidación de cursores dependientes

DBMS_STATS.AUTO_SAMPLE_SIZE permite a Oracle seleccionar una muestra adecuada. En versiones modernas normalmente es preferible a fijar manualmente un porcentaje.

DBMS_STATS.AUTO_DEGREE deja que Oracle determine el paralelismo. En producción debe evaluarse cuidadosamente porque una recopilación paralela sobre tablas grandes puede competir con las aplicaciones.

DBMS_STATS.AUTO_INVALIDATE permite que Oracle controle la invalidación progresiva de cursores, reduciendo el riesgo de hard parsing simultáneo.

6. Actualizar estadísticas de una partición

Para una sola partición:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname          => 'APPUSER',
        tabname          => 'SALES',
        partname         => 'P202608',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        granularity      => 'PARTITION',
        cascade          => DBMS_STATS.AUTO_CASCADE,
        degree           => DBMS_STATS.AUTO_DEGREE
    );
END;
/

Cuando se especifica partname, Oracle actualiza la partición indicada. Sin embargo, esto no garantiza por sí solo que las estadísticas globales de la tabla representen correctamente todas las particiones.

Para tablas particionadas de gran tamaño es recomendable evaluar las estadísticas incrementales.

7. Estadísticas incrementales para tablas particionadas

Cuando una tabla contiene cientos de particiones, recalcular todas las estadísticas globales puede consumir demasiado tiempo y recursos.

Las estadísticas incrementales permiten mantener sinopsis por partición y utilizarlas para construir estadísticas globales.

Configuración:

BEGIN
    DBMS_STATS.SET_TABLE_PREFS(
        ownname => 'APPUSER',
        tabname => 'SALES',
        pname   => 'INCREMENTAL',
        pvalue  => 'TRUE'
    );
END;
/

También puede configurarse:

BEGIN
    DBMS_STATS.SET_TABLE_PREFS(
        ownname => 'APPUSER',
        tabname => 'SALES',
        pname   => 'INCREMENTAL_STALENESS',
        pvalue  => 'USE_STALE_PERCENT'
    );
END;
/

Después se recopilan las estadísticas:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname          => 'APPUSER',
        tabname          => 'SALES',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        granularity      => 'AUTO',
        cascade          => DBMS_STATS.AUTO_CASCADE
    );
END;
/

Para que el mantenimiento incremental funcione correctamente deben utilizarse valores compatibles, como AUTO_SAMPLE_SIZE, GRANULARITY => 'AUTO' y la preferencia INCREMENTAL => 'TRUE'.

8. Actualizar todas las estadísticas de un esquema

Para recopilar estadísticas únicamente de objetos que Oracle considera necesarios:

BEGIN
    DBMS_STATS.GATHER_SCHEMA_STATS(
        ownname          => 'APPUSER',
        options          => 'GATHER AUTO',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        degree           => DBMS_STATS.AUTO_DEGREE,
        cascade          => DBMS_STATS.AUTO_CASCADE,
        no_invalidate    => DBMS_STATS.AUTO_INVALIDATE
    );
END;
/

La opción GATHER AUTO permite seleccionar objetos sin estadísticas o con estadísticas obsoletas.

Otras opciones disponibles incluyen:

  • GATHER: recopila estadísticas de todos los objetos.
  • GATHER AUTO: selecciona los objetos que las necesitan.
  • GATHER STALE: objetos con estadísticas obsoletas.
  • GATHER EMPTY: objetos sin estadísticas.
  • LIST AUTO: genera una lista sin recopilar estadísticas.
  • LIST STALE: lista objetos con estadísticas obsoletas.
  • LIST EMPTY: lista objetos sin estadísticas.

Ejemplo para obtener una lista antes de ejecutar el cambio:

DECLARE
    l_objects DBMS_STATS.OBJECTTAB;
BEGIN
    DBMS_STATS.GATHER_SCHEMA_STATS(
        ownname => 'APPUSER',
        options => 'LIST STALE',
        objlist => l_objects
    );

    FOR i IN 1 .. l_objects.COUNT LOOP
        DBMS_OUTPUT.PUT_LINE(
            l_objects(i).ownname || '.' ||
            l_objects(i).objname || ' - ' ||
            l_objects(i).objtype
        );
    END LOOP;
END;
/

Esta validación es útil en ambientes productivos porque permite estimar el alcance antes de comenzar.

9. Actualizar estadísticas de toda la base

Oracle permite recopilar estadísticas de toda la base:

BEGIN
    DBMS_STATS.GATHER_DATABASE_STATS(
        options          => 'GATHER AUTO',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        degree           => DBMS_STATS.AUTO_DEGREE,
        cascade          => DBMS_STATS.AUTO_CASCADE,
        no_invalidate    => DBMS_STATS.AUTO_INVALIDATE
    );
END;
/

Esta operación puede abarcar una gran cantidad de objetos y consumir CPU, I/O y espacio temporal. Antes de ejecutarla:

  • Estima el tiempo requerido.
  • Verifica la ventana de mantenimiento.
  • Revisa el paralelismo.
  • Confirma la carga actual.
  • Identifica tablas grandes y particionadas.
  • Valida el espacio disponible en TEMP.
  • Define un plan para restaurar estadísticas.
  • Monitorea sesiones, waits y consumo de recursos.

En la operación diaria suele ser preferible actualizar únicamente las tablas o esquemas afectados.

10. Estadísticas del diccionario y objetos fijos

Después de una instalación, upgrade o cambio importante puede ser necesario recopilar estadísticas del diccionario:

EXEC DBMS_STATS.GATHER_DICTIONARY_STATS;

Para los objetos fijos:

EXEC DBMS_STATS.GATHER_FIXED_OBJECTS_STATS;

Las estadísticas de objetos fijos deben recopilarse cuando la base haya experimentado una carga representativa. Ejecutarlas inmediatamente después del arranque puede producir información poco realista.

No conviene incluir indiscriminadamente los esquemas internos de Oracle en scripts generales de recopilación.

11. Histograms: cuándo utilizarlos

Los histogramas ayudan al optimizador cuando una columna tiene una distribución desigual y los valores del predicado producen cardinalidades muy diferentes.

Ejemplo automático:

method_opt => 'FOR ALL COLUMNS SIZE AUTO'

Oracle decide qué columnas podrían beneficiarse según el uso registrado.

Forzar histogramas:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname    => 'APPUSER',
        tabname    => 'ORDERS',
        method_opt => 'FOR COLUMNS SIZE 254 STATUS'
    );
END;
/

Forzar histogramas en todas las columnas no es recomendable. Puede:

  • Incrementar el tiempo de recopilación.
  • Aumentar el tamaño del diccionario.
  • Crear planes dependientes de valores bind.
  • Generar inestabilidad.
  • No aportar beneficios en columnas uniformes.

Después de cambiar histogramas, compara planes, cardinalidades y rendimiento real.

12. Estadísticas extendidas

Cuando varias columnas están correlacionadas, sus estadísticas individuales pueden producir estimaciones incorrectas.

Por ejemplo, STATE y CITY no son completamente independientes.

Crear un grupo de columnas:

SELECT DBMS_STATS.CREATE_EXTENDED_STATS(
           ownname   => 'APPUSER',
           tabname   => 'CUSTOMERS',
           extension => '(STATE,CITY)'
       ) AS extension_name
FROM dual;

Después:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname          => 'APPUSER',
        tabname          => 'CUSTOMERS',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO'
    );
END;
/

Consulta las extensiones:

SELECT owner,
       table_name,
       extension_name,
       extension
FROM dba_stat_extensions
WHERE owner = 'APPUSER';

13. Estadísticas pendientes

Una actualización puede cambiar los planes inmediatamente. Para reducir el riesgo, Oracle permite generar estadísticas sin publicarlas.

Configura la tabla:

BEGIN
    DBMS_STATS.SET_TABLE_PREFS(
        ownname => 'APPUSER',
        tabname => 'ORDERS',
        pname   => 'PUBLISH',
        pvalue  => 'FALSE'
    );
END;
/

Recopila las estadísticas:

BEGIN
    DBMS_STATS.GATHER_TABLE_STATS(
        ownname          => 'APPUSER',
        tabname          => 'ORDERS',
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
        method_opt       => 'FOR ALL COLUMNS SIZE AUTO',
        cascade          => DBMS_STATS.AUTO_CASCADE
    );
END;
/

Las nuevas estadísticas quedan pendientes y todavía no son utilizadas por las sesiones normales.

Para probarlas en una sesión:

ALTER SESSION SET optimizer_use_pending_statistics = TRUE;

Después pueden publicarse:

BEGIN
    DBMS_STATS.PUBLISH_PENDING_STATS(
        ownname => 'APPUSER',
        tabname => 'ORDERS'
    );
END;
/

O eliminarse:

BEGIN
    DBMS_STATS.DELETE_PENDING_STATS(
        ownname => 'APPUSER',
        tabname => 'ORDERS'
    );
END;
/

Finalmente, devuelve la preferencia si no se requiere conservarla:

BEGIN
    DBMS_STATS.SET_TABLE_PREFS(
        ownname => 'APPUSER',
        tabname => 'ORDERS',
        pname   => 'PUBLISH',
        pvalue  => 'TRUE'
    );
END;
/

Este enfoque es especialmente útil para objetos críticos cuyos planes deben probarse antes de una publicación general.

14. Bloquear y desbloquear estadísticas

Para evitar que la recopilación automática o manual modifique estadísticas estables:

EXEC DBMS_STATS.LOCK_TABLE_STATS('APPUSER', 'ORDERS');

Consulta su estado:

SELECT owner,
       table_name,
       stattype_locked
FROM dba_tab_statistics
WHERE owner = 'APPUSER'
  AND table_name = 'ORDERS';

Para desbloquearlas:

EXEC DBMS_STATS.UNLOCK_TABLE_STATS('APPUSER', 'ORDERS');

Cuando las estadísticas de una tabla están bloqueadas, también se consideran bloqueadas las estadísticas dependientes de sus columnas e índices.

No utilices el bloqueo como solución permanente para un plan inestable sin entender su causa. Los datos pueden cambiar hasta que las estadísticas bloqueadas dejen de representar la realidad.

15. Restaurar estadísticas anteriores

Oracle mantiene un historial de estadísticas que puede utilizarse como rollback.

Comprueba desde cuándo hay información disponible:

SELECT DBMS_STATS.GET_STATS_HISTORY_AVAILABILITY
FROM dual;

Consulta la retención:

SELECT DBMS_STATS.GET_STATS_HISTORY_RETENTION
FROM dual;

Lista las versiones históricas de una tabla:

SELECT table_name,
       stats_update_time
FROM dba_tab_stats_history
WHERE owner = 'APPUSER'
  AND table_name = 'ORDERS'
ORDER BY stats_update_time DESC;

Restaura las estadísticas de una tabla:

BEGIN
    DBMS_STATS.RESTORE_TABLE_STATS(
        ownname         => 'APPUSER',
        tabname         => 'ORDERS',
        as_of_timestamp => TO_TIMESTAMP(
            '2026-08-31 22:00:00',
            'YYYY-MM-DD HH24:MI:SS'
        ),
        force            => FALSE
    );
END;
/

Restaura un esquema:

BEGIN
    DBMS_STATS.RESTORE_SCHEMA_STATS(
        ownname         => 'APPUSER',
        as_of_timestamp => SYSTIMESTAMP - INTERVAL '2' HOUR
    );
END;
/

Después de restaurar, valida:

  • LAST_ANALYZED.
  • Número de filas y bloques.
  • Histogramas.
  • Plan hash value.
  • Tiempo de ejecución.
  • Buffer gets.
  • Cursores existentes.
  • Rendimiento de otras sentencias que utilicen el objeto.

16. ¿Se pueden exportar e importar las estadísticas?

Sí. Oracle permite exportar estadísticas a una tabla mediante DBMS_STATS. Después, esa tabla puede trasladarse a otro ambiente usando Data Pump.

Este mecanismo puede utilizarse para:

  • Transferir estadísticas de producción a QA.
  • Respaldarlas antes de una actualización.
  • Conservar una línea base antes de una carga masiva.
  • Reproducir planes de ejecución en un laboratorio.
  • Migrar estadísticas junto con una aplicación.
  • Recuperar rápidamente una configuración conocida.

17. Crear la tabla de estadísticas

En el esquema que almacenará las estadísticas:

BEGIN
    DBMS_STATS.CREATE_STAT_TABLE(
        ownname => 'STATADMIN',
        stattab => 'OPTIMIZER_STATS_BACKUP',
        tblspace => 'USERS'
    );
END;
/

Esta tabla tiene una estructura especial. No debe crearse manualmente con CREATE TABLE.

18. Exportar estadísticas de una tabla

BEGIN
    DBMS_STATS.EXPORT_TABLE_STATS(
        ownname  => 'APPUSER',
        tabname  => 'ORDERS',
        partname => NULL,
        stattab  => 'OPTIMIZER_STATS_BACKUP',
        statid   => 'ORDERS_BEFORE_RELEASE',
        cascade  => TRUE,
        statown  => 'STATADMIN'
    );
END;
/

STATID funciona como una etiqueta que permite conservar varias versiones en la misma tabla.

19. Importar estadísticas de una tabla

BEGIN
    DBMS_STATS.IMPORT_TABLE_STATS(
        ownname       => 'APPUSER',
        tabname       => 'ORDERS',
        partname      => NULL,
        stattab       => 'OPTIMIZER_STATS_BACKUP',
        statid        => 'ORDERS_BEFORE_RELEASE',
        cascade       => TRUE,
        statown       => 'STATADMIN',
        no_invalidate => DBMS_STATS.AUTO_INVALIDATE,
        force         => FALSE
    );
END;
/

Esta operación publica las estadísticas importadas en el diccionario y puede influir en los planes de ejecución.

20. Exportar e importar un esquema

Exportación:

BEGIN
    DBMS_STATS.EXPORT_SCHEMA_STATS(
        ownname => 'APPUSER',
        stattab => 'OPTIMIZER_STATS_BACKUP',
        statid  => 'APPUSER_BASELINE',
        statown => 'STATADMIN'
    );
END;
/

Importación:

BEGIN
    DBMS_STATS.IMPORT_SCHEMA_STATS(
        ownname       => 'APPUSER',
        stattab       => 'OPTIMIZER_STATS_BACKUP',
        statid        => 'APPUSER_BASELINE',
        statown       => 'STATADMIN',
        no_invalidate => DBMS_STATS.AUTO_INVALIDATE,
        force         => FALSE
    );
END;
/

21. Exportar e importar todas las estadísticas de la base

Exportación:

BEGIN
    DBMS_STATS.EXPORT_DATABASE_STATS(
        stattab => 'OPTIMIZER_STATS_BACKUP',
        statid  => 'DATABASE_BASELINE',
        statown => 'STATADMIN'
    );
END;
/

Importación:

BEGIN
    DBMS_STATS.IMPORT_DATABASE_STATS(
        stattab       => 'OPTIMIZER_STATS_BACKUP',
        statid        => 'DATABASE_BASELINE',
        statown       => 'STATADMIN',
        no_invalidate => DBMS_STATS.AUTO_INVALIDATE,
        force         => FALSE
    );
END;
/

Importar estadísticas de toda una base puede generar cambios de planes en numerosos objetos. Esta operación requiere una ventana controlada, pruebas previas y un procedimiento de rollback.

22. Transferir la tabla con Data Pump

Una vez exportadas las estadísticas a STATADMIN.OPTIMIZER_STATS_BACKUP, traslada la tabla al ambiente destino.

Exportación desde el sistema operativo:

expdp system \
  directory=DATA_PUMP_DIR \
  dumpfile=optimizer_stats_backup.dmp \
  logfile=optimizer_stats_backup_exp.log \
  tables=STATADMIN.OPTIMIZER_STATS_BACKUP

Importación en el destino:

impdp system \
  directory=DATA_PUMP_DIR \
  dumpfile=optimizer_stats_backup.dmp \
  logfile=optimizer_stats_backup_imp.log \
  tables=STATADMIN.OPTIMIZER_STATS_BACKUP

Después ejecuta IMPORT_TABLE_STATS, IMPORT_SCHEMA_STATS o IMPORT_DATABASE_STATS, según corresponda.

En ambientes con nombres de esquema diferentes puede ser necesario evaluar REMAP_SCHEMA. Debe mantenerse clara la diferencia entre:

  • El propietario del objeto cuyas estadísticas se importarán.
  • El propietario de la tabla que contiene el respaldo.

23. Limitaciones al mover estadísticas entre ambientes

Importar estadísticas no reproduce completamente el comportamiento de producción.

También influyen:

  • Volumen real de datos.
  • Parámetros del optimizador.
  • Versión y Release Update.
  • Configuración de CPU.
  • Memoria.
  • Velocidad del almacenamiento.
  • Paralelismo.
  • Bind variables.
  • NLS.
  • Servicios.
  • Adaptive Cursor Sharing.
  • SQL Plan Baselines.
  • Estadísticas del sistema.
  • Distribución real de datos.
  • Objetos o índices que no existen en el destino.

Las estadísticas importadas ayudan a reproducir estimaciones y planes, pero no sustituyen una prueba de rendimiento representativa.

24. Verificar la recopilación automática

Comprueba el estado del cliente automático:

SELECT client_name,
       status,
       window_group,
       attributes
FROM dba_autotask_client
WHERE client_name = 'auto optimizer stats collection';

Consulta las ventanas:

SELECT window_name,
       enabled,
       repeat_interval,
       duration,
       resource_plan
FROM dba_scheduler_windows
ORDER BY window_name;

Revisa las operaciones recientes:

SELECT operation,
       target,
       start_time,
       end_time,
       status,
       job_name,
       notes
FROM dba_optstat_operations
ORDER BY start_time DESC
FETCH FIRST 30 ROWS ONLY;

Para obtener detalles:

SELECT DBMS_STATS.REPORT_STATS_OPERATIONS(
           since  => SYSTIMESTAMP - INTERVAL '1' DAY,
           until  => SYSTIMESTAMP,
           detail_level => 'TYPICAL'
       )
FROM dual;

25. Monitorear una recopilación en ejecución

Puedes localizar las sesiones relacionadas:

SELECT sid,
       serial#,
       username,
       program,
       module,
       event,
       state,
       sql_id
FROM v$session
WHERE module LIKE '%DBMS_STATS%'
   OR action LIKE '%DBMS_STATS%';

También revisa operaciones largas:

SELECT sid,
       serial#,
       opname,
       target,
       sofar,
       totalwork,
       units,
       elapsed_seconds,
       time_remaining
FROM v$session_longops
WHERE totalwork > 0
  AND sofar < totalwork
ORDER BY start_time;

Durante una recopilación grande monitorea:

top
vmstat 1
iostat -xz 1

Y desde Oracle:

SELECT event,
       total_waits,
       time_waited_micro / 1000000 AS time_waited_seconds
FROM v$system_event
WHERE wait_class <> 'Idle'
ORDER BY time_waited_micro DESC
FETCH FIRST 20 ROWS ONLY;

26. Procedimiento recomendado para producción

Antes del cambio

  1. Identifica exactamente los objetos afectados.
  2. Revisa LAST_ANALYZED y STALE_STATS.
  3. Verifica estadísticas bloqueadas.
  4. Consulta las preferencias actuales.
  5. Registra los planes de ejecución importantes.
  6. Exporta las estadísticas actuales.
  7. Confirma la disponibilidad del historial.
  8. Revisa la carga de la base.
  9. Define criterios de éxito y rollback.

Durante el cambio

  1. Utiliza AUTO_SAMPLE_SIZE.
  2. Limita el alcance al objeto necesario.
  3. Controla el paralelismo.
  4. Monitorea CPU, I/O, TEMP y waits.
  5. Registra inicio, fin y duración.
  6. Evita recopilar simultáneamente con procesos críticos.
  7. Considera estadísticas pendientes para objetos sensibles.

Después del cambio

  1. Valida LAST_ANALYZED.
  2. Revisa NUM_ROWS, BLOCKS y SAMPLE_SIZE.
  3. Confirma las estadísticas de índices.
  4. Verifica histogramas.
  5. Compara planes y cardinalidades.
  6. Ejecuta pruebas funcionales.
  7. Revisa DB Time y waits.
  8. Restaura las estadísticas anteriores si aparece una regresión.

27. Errores comunes

Utilizar ANALYZE TABLE para estadísticas del optimizador

Para estadísticas modernas del optimizador debe utilizarse DBMS_STATS. El comando ANALYZE conserva otros usos administrativos, pero no debe ser el mecanismo normal de mantenimiento del CBO.

Actualizar toda la base ante cualquier incidente

Puede consumir recursos y cambiar numerosos planes sin resolver la causa original.

Utilizar un porcentaje fijo sin justificación

AUTO_SAMPLE_SIZE normalmente produce mejores resultados que un porcentaje elegido arbitrariamente.

Forzar histogramas en todas las columnas

Puede aumentar el tiempo, el almacenamiento y la inestabilidad sin aportar valor.

Configurar no_invalidate => FALSE indiscriminadamente

Puede invalidar muchos cursores al mismo tiempo y provocar una tormenta de hard parsing.

Utilizar paralelismo excesivo

Una recopilación puede competir con la carga productiva por CPU, I/O y TEMP.

Importar estadísticas sin validar compatibilidad

Los objetos, particiones, índices y versiones deben ser compatibles.

No preparar un rollback

Antes de modificar estadísticas críticas deben exportarse o comprobarse en el historial.

Conclusión

Actualizar estadísticas en Oracle no es simplemente ejecutar GATHER_SCHEMA_STATS. Es una operación que puede modificar las decisiones del optimizador y cambiar el rendimiento de toda una aplicación.

La estrategia más segura consiste en:

  1. Determinar qué objetos realmente necesitan estadísticas.
  2. Recopilar solamente el alcance necesario.
  3. Usar las opciones automáticas de Oracle como punto de partida.
  4. Probar estadísticas pendientes en objetos críticos.
  5. Exportar o conservar una versión anterior.
  6. Comparar planes antes y después.
  7. Monitorear el impacto real.
  8. Restaurar las estadísticas si aparece una regresión.

Oracle permite exportar e importar estadísticas de tablas, esquemas y bases completas mediante DBMS_STATS. Esta capacidad resulta especialmente útil para respaldar estadísticas antes de un cambio, migrarlas entre ambientes o reproducir planes de ejecución.

La clave no es tener las estadísticas más recientes, sino disponer de estadísticas representativas que permitan al optimizador estimar correctamente el trabajo necesario.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *