Cuando un proceso bloquea registros o tablas de una base de datos puede ocurrir que los tests de servidor web y servidor de aplicaciones no den problemas mientras que la web en cambio no funciona… o bien pueden dar error y creamos que dichos servicios se han degradado y reiniciamos servicios o empezamos a buscar el error en los logs, lo que nos hace perder un tiempo valioso.

Por eso creo importante tener un test de sesiones que nos diga no solo las sesiones activas que tenemos en la base de datos sino tambien los bloqueos que pueden haber en un momento determinado.

En Oracle tenemos la vista v$session que contiene la columna blocking_session, que indica que un proceso determinado depende de un recurso cogido por otro proceso.

select process, sid, blocking_session from v$session where blocking_session is not null;

Con esto obtenemos el proceso del sistema operativo correspondiente, la sesión bloqueada y la sesión que la bloquea…

Si queremos saber que sentencia SQL corresponde a la sesión que bloquea podemos hacer:

select a.sid, b.sql_text
from v$session a, v$sqlarea b
where a.sql_address=b.address
and a.sid = SESION;

O directamente mezclar los dos conceptos ya en uno:

select a.process, a.sid, a.blocking_session, b.sql_text
from v$session a, v$sqlarea b
where a.sql_address=b.address
and a.blocking_session is not null;

Visto esto, pongo aquí el script que tengo puesto en Nagios que lanza queries contra las bases de datos. La llamada seria tal que:

/opt/nagios/libexec/check_oracle_sessions.sh 192.168.100.100:1521:sid nagios/nagiospasswd

Y el script:

#!/bin/sh

STATE_OK=0
STATE_WARNING=1
STATE_CRITICAL=2
STATE_UNKNOWN=3
STATE_DEPENDENT=4

DATABASE=$1
USERPASS=$2

TNS_ADMIN=/opt/sqlplus; export TNS_ADMIN
SQLPLUS=”/opt/sqlplus/sqlplus -s
${USERPASS}@${DATABASE}”

#—————————
# Total de sesiones activas
#—————————

echo “set pages 0
set lines 20
set linesize 9999
set head off
set echo off
set verify off
set feedback off
select count(*) from v$session where status=’ACTIVE’;
exit” > /tmp/commands.$$.tmp
SESSIONS_ACTIVE=`$SQLPLUS < /tmp/commands.$$.tmp | awk ‘{print $1}’`
rm /tmp/commands.$$.tmp
 
echo “set pages 0
set lines 20
set linesize 9999
set head off
set echo off
set verify off
set feedback off
select count(*)
from v$session
where blocking_session is not NULL;
exit” > /tmp/commands.$$.tmp
SESSIONS_BLOCKED_COUNT=`$SQLPLUS < /tmp/commands.$$.tmp | awk ‘{print $1}’`
rm /tmp/commands.$$.tmp
 
echo “set pages 0
set lines 20
set linesize 9999
set head off
set echo off
set verify off
set feedback off
select ‘Session ‘ || blocking_session || ‘ blocks session ‘ || sid || ‘ for ‘ || trunc(seconds_in_wait/60) || ‘ min.’
from v$session
where blocking_session is not NULL
order by blocking_session;
exit” > /tmp/commands.$$.tmp
SESSIONS_BLOCKED_TEXT=`$SQLPLUS < /tmp/commands.$$.tmp`
rm /tmp/commands.$$.tmp
 
 
STATE=${STATE_OK}
 
if [ -z “${SESSIONS_ACTIVE}” ]; then SESSIONS_ACTIVE=0; fi
 
if [ “${SESSIONS_ACTIVE}” -lt 10 ] && [ “${SESSIONS_ACTIVE}” -ge 30 ]; then STATE=${STATE_CRITICAL}; fi
 
if [ “${SESSIONS_BLOCKED_COUNT}” -gt 0 ]; then
        echo “Oracle Sessions – Active: ${SESSIONS_ACTIVE} – Blocked: ${SESSIONS_BLOCKED_COUNT} ($SESSIONS_BLOCKED_TEXT) ‘active_sessions’=${SESSIONS_ACTIVE} ‘blocked_sessions’=${SESSIONS_BLOCKED_COUNT}”
        STATE=${STATE_CRITICAL}
else
        echo “Oracle Sessions – Active: ${SESSIONS_ACTIVE} – Blocked: ${SESSIONS_BLOCKED_COUNT} |’active_sessions’=${SESSIONS_ACTIVE} ‘blocked_sessions’=${SESSIONS_BLOCKED_COUNT}”
fi
 
exit $STATE