Objetivos
- Describir las Secciones de Oracle.
- Consultar las secciones activas.
- Conocer los métodos para terminar y/o desconectar las sesiones activas.
- Ver y terminar los bloqueos de Transacciones.
Las Sesiones de Oracle
Una sesión es la conexión establecida entre una aplicación y la Base de Datos Oracle, junto con los recursos y objetos asociados a esa conexión.
Es posible consultar y obtener información sobre las sesiones activas mediante las vistas V$SESSION y GV$SESSION. Estas vistas contienen, entre otros, los campos SID, SERIAL# e INST_ID, que son útiles para identificar y finalizar (kill) sesiones específicas cuando sea necesario.
SELECT vs.sid
, vs.serial#
, vs.*
FROM sys.v$session vs;
SELECT gvs.sid
, gvs.serial#
, gvs.inst_id
, gvs.*
FROM sys.gv$session gvs;
Los Bloqueos en Transacciones
Los bloqueos en transacciones son mecanismos de control de concurrencia que utiliza el sistema de base de datos para proteger la integridad de los datos cuando múltiples sesiones intentan acceder o modificar los mismos recursos al mismo tiempo.
Un bloqueo ocurre cuando una transacción impide temporalmente que otra transacción lea o modifique un dato, hasta que la primera transacción finalice mediante COMMIT o ROLLBACK. Esto evita inconsistencias y conflictos en los datos.
Oracle proporciona varias vistas dinámicas que permiten monitorear los bloqueos de transacciones dentro de la base de datos. Una de las más utilizadas es V$LOCK, que muestra los bloqueos activos entre sesiones.
Sin embargo, esta vista no proporciona información directa sobre los objetos bloqueados (como el nombre de la tabla o el recurso específico). Por esta razón, suele complementarse con otras vistas como DBA_BLOCKERS, DBA_WAITERS, V$SESSION y V$ACCESS, las cuales permiten obtener una visión más completa de las sesiones involucradas y del origen del conflicto.
1. Conectado con HR ejecutamos la consulta:
SELECT employee_id
, first_name
, last_name
, email
FROM hr.employees
WHERE employee_id = 100;

2. Actualizamos el campo email, no ejecutamos COMMIT alguno y re ejecutamos la anterior consulta:
UPDATE hr.employees
SET email = email||'@company.com'
WHERE employee_id = 100;

3. Conectado con un segundo usuario (SYS en mi caso) ejecutamos los mismos script anteriores, notamos que la consulta no muestra la actualización del campo EMAIL y el update no concluye el procesamiento.

4. Ahora conectado con un tercel usuario (SYSTEM en mi caso) ejecutamos la siguiente consulta:
SELECT
(
SELECT s.username
FROM sys.v$session s
WHERE s.sid=bker.sid
) AS usuario_bloqueador,
bker.SID AS sid_bloqueador,
(
SELECT s.username
FROM sys.v$session s
WHERE s.sid=bked.sid
) AS usuario_bloqueado,
bked.SID AS sid_bloqueado
FROM sys.v$lock bker
JOIN sys.v$lock bked
ON (
bker.id1 = bked.id1
AND bker.id2 = bked.id2)
WHERE bker.block = 1
AND bked.request > 0;

La imagen muestra el resultado de una consulta que identifica sesiones bloqueadoras y sesiones bloqueadas en la base de datos.
En este caso específico:
| USUARIO_BLOQUEADOR | SID_BLOQUEADOR | USUARIO_BLOQUEADO | SID_BLOQUEADO |
|---|---|---|---|
| HR | 742 | SYS | 1107 |
Esto indica que:
- La sesión 742, perteneciente al usuario HR, está bloqueando un recurso.
- La sesión 1107, perteneciente al usuario SYS, está esperando ese mismo recurso y por lo tanto se encuentra bloqueada.
La consulta funciona comparando registros de V$LOCK para encontrar sesiones que poseen un bloqueo (block = 1) y otras que están solicitando ese mismo recurso (request > 0), relacionándolas mediante los identificadores internos ID1 y ID2, que representan el recurso bloqueado. Luego consulta V$SESSION para obtener los nombres de los usuarios asociados a cada SID.
La Vista V$LOCKED_OBJECT
Oracle proporciona la vista dinámica V$LOCKED_OBJECT, la cual permite identificar con mayor detalle las transacciones que mantienen bloqueos en la base de datos. A diferencia de otras vistas, esta muestra el objeto específico que está bloqueado, lo que facilita determinar qué tabla u objeto está involucrado en el conflicto.
La siguiente consulta muestra las mismas sesiones bloqueadas más el objeto que contiene el bloqueo:
SELECT
o.owner||'.'||o.object_name AS objeto
,o.object_type AS tipo_bojeto
,s.username AS usuario_conexion
,s.sid
,s.serial#
,s.status
, DECODE(s.status, 'INACTIVE', 'BLOQUEADOR', 'ACTIVE', 'BLOQUEDADO', 'DESCONOCIDO') AS DESR_USUARIO
FROM
sys.gv$locked_object bo
JOIN sys.gv$session s
ON ( s.sid = bo.session_id)
JOIN sys.dba_objects o
ON (bo.object_id = o.object_id
AND bo.inst_id = s.inst_id);

Eliminando Bloqueos de Base Datos
Oracle ofrece varios métodos para desbloquear una transacción. Puede utilizar las sentencias:
ALTER SYSTEM KILL SESSION 'SID, SERIAL#' [IMMEDIATE];
La anterior sentencia revierte las transacciones en curso, libera los bloqueos y recupera parcialmente los recursos utilizados; si no incluimos la clausula IMMEDIATE la sesión es marcada como ‘marked for kill’ para que ésta se elimine tan pronto como le sea posible, teniendo en cuenta que dicho proceso puede tomar varios minutos en completarse.
ALTER SYSTEM DISCONNECT SESSION 'SID, SERIAL#' [POST_TRANSACTION | IMMEDIATE];
La pasada sentencia es un método alternativo para eliminar transacciones bloqueadas. Mientras que KILL SESSION solicita a la sesión que se auto elimine automáticamente, DISCONNECT SESSION termina el proceso del servidor dedicado. Lo que es igual a terminar el proceso desde el sistema operativo.
La cláusula POST_TRANSACTION espera a que se completen las transacciones en curso para luego desconectar la sesión, la cláusula IMMEDIATE desconecta la sesión y las transacciones en curso se revierten inmediatamente.
Tener pendiente que en la sintaxis [ ] indica que ambas cláusulas son opcionales, pero esto no es así, se deben especificar una o ambas, de lo contrario recibiría un error. Si ambas cláusulas son incluidas IMMEDIATE seria ignorada.
Ejemplos:
ALTER SYSTEM KILL SESSION '742, 58463' IMMEDIATE;
ALTER SYSTEM DISCONNECT SESSION '742, 58463' IMMEDIATE;
Las dos sentencias anteriores muestran como terminar la sesión bloqueadora.
SET SERVEROUTPUT ON
DECLARE
CURSOR cur_sessions IS
SELECT
vs.sid
, vs.serial#
FROM sys.v$session vs
WHERE sid <> SYS_CONTEXT('USERENV', 'SID')
;
BEGIN
FOR i IN cur_sessions LOOP
BEGIN
EXECUTE IMMEDIATE 'ALTER SYSTEM KILL SESSION '''||i.sid||', '||i.serial#||''' IMMEDIATE';
DBMS_OUTPUT.PUT_LINE('SESSION '||i.sid||'-'||i.serial#||' KILLED');
EXCEPTION
WHEN OTHERS THEN
BEGIN
EXECUTE IMMEDIATE 'ALTER SYSTEM DISCONNECT SESSION '''||i.sid||', '||i.serial#||''' IMMEDIATE';
DBMS_OUTPUT.PUT_LINE('SESSION '||i.sid||'-'||i.serial#||' DISCONNECTED');
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END;
END LOOP;
END;

El bloque PL/SQL anterior consulta todas las sesiones de base de datos diferentes a la sesión actual y utiliza las sentencias KILL SESSION y DISCONNECT SESSION para eliminarlas o desconectarlas.

