jueves, 24 de septiembre de 2009

Reporte de Tablas sin estadisticas o con estadisticas viejas (stale) para una sesion dada

Una gran parte de los problemas repentinos de performance se da porque el optimizador arma un plan ineficiente producto de que las estadisticas actuales de las tablas, particiones o subparticiones involucradas no reflejan la realidad. Esto se debe a que los segmentos sufrieron un cambio de datos mayor al 10% y no se actualizaron las estadisticas en el catalogo. Uno de los datos con el que comenzamos a analizar este tipo de problema es el sid asociado a la sesion que esta ejecutando con demoras. Teniendo el sid el siguiente paso es ver la sentencia en ejecución y chequear si los segmentos referenciados cuentan con estadisticas frescas. Si la sentencia en cuestion es compleja y referencia varios segmentos nos demorará un tiempo revisar cada uno de los segmentos. Por tal motivo pensé en armar un query que basado principalmente en la vista dinamica v$sql_plan, obtiene los segmentos usados en los paths del plan de ejecucion y luego verifica si estan STALE o si estan nulas usando la vista dba_tab_statistics.
El script de abajo permite determinar automaticamente que tablas, particiones y subparticiones tienen estadisticas desactualizadas para un sid determinado.


set line 120
set pagesize 999
set verify off

col owner format a15
col table_name format a30
col partition_name format a30
col subpartition_name format a30

PROMPT
PROMPT "---------------------------------------------"
PROMPT "Reporte de Tablas con estadisticas STALE "
PROMPT "o nulas para una sesion dada "
PROMPT "---------------------------------------------"
ACCEPT sid PROMPT "Ingrese SID a evaluar: "

select st.owner owner,
st.table_name table_name,
st.partition_name partition_name,
st.subpartition_name subpartition_name
from v$session s,
v$sql_plan p,
dba_tab_statistics st
where s.sql_id = p.sql_id
and p.object_owner = st.owner
and p.object_name = st.table_name
and s.sid = &sid
and nvl(st.stale_stats,'YES') = 'YES'
and ((nvl(st.partition_position,1)
between
(case when (REGEXP_LIKE(nvl(p.partition_start,'a'),'[^[:digit:]]'))
then 1
else to_number(p.partition_start) end)
and (case when
(REGEXP_LIKE(nvl(p.partition_stop,'a'),'[^[:digit:]]'))
then 10000
else to_number(p.partition_stop) end))
or
(nvl(st.subpartition_position,1) between
(case when (REGEXP_LIKE(nvl(p.partition_start,'a'),'[^[:digit:]]'))
then 1
else to_number(p.partition_start) end)
and (case when
(REGEXP_LIKE(nvl(p.partition_stop,'a'),'[^[:digit:]]')) then 10000
else to_number(p.partition_stop) end))
)
/

set verify on


IMPORTANTE: Para asegurar que esten impactados los cambios mas recientes en la
vista dba_tab_statistics es recomendable flushear la memoria de la
siguiente forma: dbms_stats.flush_database_monitoring_info.

No hay comentarios:

Publicar un comentario