martes, 17 de noviembre de 2015

SIMULAR ACTIVE SESSION HISTORY- SASH - para Oracle Standard Edition (por Alejandro Aguirrez)


Durante mis años como trabajando como dba ORACLE en muchas oportunidades he necesitado  indicadores y métricas con mayor granularidad que los snapshops cada 1 hora o , en ambientes mas críticos,  cada 30 minutos para poder diagnosticar y aislar  un problema  . Oracle presento una solución con la aparicion de ASH (Active Session History ) a partir de la versión 10g en adelante. Desafortunadamente ASH solo está disponible en las versión Enterprise (EE)  y con el Diagnostic Pack licenciado. Es decir que en versiones "Standard Edition" (SE)y "Standard One" (SO) si bien la vista existe los datos no son colectados.

Como todos sabemos el costo de las licencias para EE muy superior al de SE y SO. Por esta razon muchas empresas optan por las verisones Standard que se ajusten a las prestaciones que necesita. Sin embargo como sabemos a nivel diagnostico y Performance deja a los dba sin AWR ni ASH .

Buscando  llegue  un blog Kyle Hailey donde presentaba SASH (Simulated ASH). Esta herramienta simulaba el collect de ASH mediante jobs y emulaba un catalogo de ASH. La idea me pareció excelente asi que empece a realizarle mejoras para poder  (desde el 2010 que no se actualizaba el blog) ya que como toda version inicial tenía varios bugs.
Ahora con la version 2.1 considero que esta lo suficiente madura para poder compartirla e ir mejorandola con las experiencias de los que la utilicen.


Prerequisitos

  1. Versión de base de datos 10.2 en adelante (versiones anteriores a esta no fue probado por ende no estaría homologado pero no quiere decir que no funcione)
  2. Tablespace Temporal TEMP . En caso de necesitar usar otro tablespace temporal  se debe modificar el script repo_0_user.sql con el nombre del tablespace temporal desado.
  3. Tablespace de Datos dedicado para el repositorio de SASH.
  4. Acceso como SYS a la base de datos.

Caracteristicas

  1. Muestras en tiempo real con un intervalo configurable ( En mis pruebas la configuración ideal es cada 5 segundos ).
  2. Los datos se visualizan el vista SASH.V$ACTIVE_SESSION_HISTORY
  3. Los planes de ejecución se pueden visualizar en la tabla SASH.SASH_SQLPLANS


Instalación

Los pasos están en el archivo Manual_SASH.


Sentencias Básicas para utilizar la herramienta:

1 - Sentencias más consumidoras en un intervalo de tiempo

select sql_id as hash_value,sqlid,SQL_PLAN_HASH_VALUE,COUNT(*)*2 AS total_wait_time, round((count(*)*2)/(sum(count(*)*2) over() ) *100,2) pct
from sash.V$active_session_history  a
where a.sample_time >= to_date('03/02/2015 12:30','DD/MM/YYYY HH24:MI')
and a.sample_time <= to_date('03/02/2015 15:30','DD/MM/YYYY HH24:MI')
and sql_id!=0
group by a.sql_id ,a.sqlid,a.SQL_PLAN_HASH_VALUE
order by total_wait_time desc;


2 - Sentencias mas consumidoras en un intervalo de tiempo con sus evento asociado

select NVL(a.event, 'ON CPU') AS event,sql_id hash_value,sqlid,SQL_PLAN_HASH_VALUE,
COUNT(*)*2 AS total_wait_time, round((count(*)*2)/(sum(count(*)*2) over() ) *100,2) pct
from sash.V$active_session_history  a
where a.sample_time >= to_date('03/02/2015 12:30','DD/MM/YYYY HH24:MI')
and a.sample_time <= to_date('03/02/2015 15:30','DD/MM/YYYY HH24:MI')
and sql_id!=0
group by a.event,a.sql_id ,a.sqlid,a.SQL_PLAN_HASH_VALUE
order by total_wait_time desc;


3 - Eventos en un intervalo de tiempo

select  NVL(a.event, 'ON CPU') AS event
COUNT(*)*2 AS total_wait_time, round((count(*)*2)/(sum(count(*)*2) over() ) *100,2) pct
from sash.V$active_session_history  a
where a.sample_time >= to_date('03/02/2015 12:30','DD/MM/YYYY HH24:MI')
and a.sample_time <= to_date('03/02/2015 15:30','DD/MM/YYYY HH24:MI')
group by a.event
order by total_wait_time desc;


4 - obtener planes de ejecución

SELECT '| Operation | PHV/Object Name | Rows | Bytes| Cost |'
as "Optimizer Plan:"
FROM dual
UNION ALL
SELECT * FROM (SELECT
rpad('|'||substr(lpad(' ',1*(depth-1))||operation||
--rpad('|'||substr(lpad(' ',1)||operation||
decode(options, null,'',' '||options), 1, 32), 33, ' ')||'|'||
rpad(decode(id, 0, '----- '||to_char(hash_value)||' [' ||']-----'
, substr(decode(substr(object_name, 1, 7), 'SYS_LE_', null,
object_name)
||' ',1, 20)), 21, ' ')||'|'||
lpad(decode(cardinality,null,' ',
decode(sign(cardinality-1000), -1, cardinality||' ',
decode(sign(cardinality-1000000), -1, trunc(cardinality/1000)||'K',
decode(sign(cardinality-1000000000), -1, trunc(cardinality/1000000)||'M',
trunc(cardinality/1000000000)||'G')))), 7, ' ') || '|' ||
lpad(decode(bytes,null,' ',
decode(sign(bytes-1024), -1, bytes||' ',
decode(sign(bytes-1048576), -1, trunc(bytes/1024)||'K',
decode(sign(bytes-1073741824), -1, trunc(bytes/1048576)||'M',
trunc(bytes/1073741824)||'G')))), 6, ' ') || '|' ||
lpad(decode(cost,null,' ',
decode(sign(cost-10000000), -1, cost||' ',
decode(sign(cost-1000000000), -1, trunc(cost/1000000)||'M',
trunc(cost/1000000000)||'G'))), 8, ' ') || '|' as "Explain plan"
FROM sash.SASH_SQLPLANS
WHERE  hash_value =PLAN_HASH_VALUE
ORDER BY hash_value,id);


5 - Obtener el texto de una sentencia (en RAC puede aparecer dos veces)

select * from SASH.SASH_SQLTXT where sql_id=HASH_VALUE_SENTENCIA order by ADDRESS,PIECE;



Espero que les sea de utilidad!! :)