Estadísticas. Probamos antes de actualizarlas?

Hay casos en los que existe temor a la hora de actualizar las estadísticas.

Normalmente son casos en los que llevan sin actualizarse meses, incluso años por miedo a éstas, o simplemente se quiere probar un cambio en concreto en relación a un plan de ejecución y se quiere ser cauto.

Para ello tenemos una opción muy interesante en Oracle que nos permite probar las estadísticas que queremos antes de verse reflejadas finalmente en los objetos.

¿En qué consiste el método? Básicamente pasaremos las estadísticas pero no las publicaremos ( no serán aún efectivas) pero podremos probar el impacto en el plan o los planes de ejecución que queramos validar antes de darles el ok.

Expongo el procedimiento para una tabla:

alter session set nls_date_format='dd/mm/yyyy hh24:mi:ss';
select table_name, last_analyzed,num_rows from dba_tables where owner='PRU' and table_name='TABLAPRU';

TABLE_NAME         LAST_ANALYZED         NUM_ROWS
------------------ ------------------- ----------
TABLAPRU           24/06/2023 22:07:59      11349


select count(*) from PRU.TABLAPRU; 

  COUNT(*)
----------
     12616

-- Deshabilitamos la publicación, para que no apliquen al ejecutarlas
select dbms_stats.get_prefs('PUBLISH', 'PRU', 'TABLAPRU' ) FROM DUAL;

DBMS_STATS.GET_PREFS('PUBLISH','PRU','TABLAPRU')                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
---------------------------------------------------
TRUE

exec dbms_stats.set_table_prefs('PRU','TABLAPRU','PUBLISH','FALSE');

PL/SQL procedure successfully completed.



select dbms_stats.get_prefs('PUBLISH', 'PRU', 'TABLAPRU' ) FROM DUAL;

DBMS_STATS.GET_PREFS('PUBLISH','PRU','TABLAPRU')                                                                                                                                                  
--------------------------------------------------------
FALSE

-- Ejecutamos estadísticas
exec DBMS_STATS.GATHER_TABLE_STATS (ownname => 'PRU' , tabname => 'TABLAPRU',cascade => true, estimate_percent => dbms_stats.auto_sample_size, method_opt=>'FOR ALL COLUMNS SIZE AUTO');
PL/SQL procedure successfully completed.



-- Comprobar que siguen intactas
select table_name, last_analyzed,num_rows from dba_tables where owner='PRU' and table_name='TABLAPRU';

TABLE_NAME        LAST_ANALYZED         NUM_ROWS
------------------------------------- ----------
TABLAPRU          24/06/2023 22:07:59      11349

-- Estadisticas pendientes
SELECT table_name, last_analyzed from DBA_TAB_PENDING_STATS where table_name='TABLAPRU';

TABLE_NAME         LAST_ANALYZED      
------------------ -------------------
TABLAPRU           07/11/2023 13:07:48

Probaríamos el plan o planes de ejecución que queremos validar con el cambio:

alter session set optimizer_use_pending_statistics=true;
select /*+ gather_plan_statistics */ 
from .....;

select * from table(dbms_xplan.display_cursor(format=>'basic +rows +rowstats last'));
alter session set optimizer_use_pending_statistics=false

Si lo damos por válido sólo nos quedaría publicarlas:

exec dbms_stats.publish_pending_stats('PRU','TABLAPRU',no_invalidate=>false);

En caso de necesitarlo recordar que se pueden recuperar del histórico. De igual manera siempre recomiendo hacer un backup previo de éstas (DBMS_STATS.EXPORT_SCHEMA_STATS)

exec dbms_stats.restore_table_stats('PRU','TABLAPRU',sysdate-1,no_invalidate=>false);