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
- 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)
- 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.
- Tablespace de Datos dedicado para el repositorio de SASH.
- Acceso como SYS a la base de datos.
- Muestras en tiempo real con un intervalo configurable ( En mis pruebas la configuración ideal es cada 5 segundos ).
- Los datos se visualizan el vista SASH.V$ACTIVE_SESSION_HISTORY
- 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!! :)