Cómo Identificar Un Bloqueo en Oracle
Cómo Identificar Un Bloqueo en Oracle
Cómo Identificar Un Bloqueo en Oracle
Table created.
SQL> commit;
Commit complete.
SID
-----------------------
142
Table(s) Locked.
SID
-----------------------
119
HOLDING_SESSION
---------------
142
En este podemos ver que existen una sesión bloqueadas por el usuario 142.
SID SERIAL#
---------- ----------
142 63166
Ahora si podemos eliminar esa sesión (No es conveniente estar matando todas
las sesiones que estén bloqueando usuario, debemos siempre de identificar el
problema que lo causa, alguna transacción abierta dejada por algún
desarrollador, un error en la aplicación, etc.)
System altered.
no rows selected
Quisiera anexar algunos queries más que también nos muestran los bloqueos:
select l1.sid, ' IS BLOCKING ', l2.sid
from v$lock l1, v$lock l2
where l1.block =1 and l2.request > 0
and l1.id1=l2.id1
and l1.id2=l2.id2;
El programa Oracle utiliza una función de bloqueo para garantizar que más de una función
actualice los datos a la vez y, de esta manera, mantener la integridad de la información. El
bloqueo ocurre en muchos niveles, incluyendo las filas, tablas y espacios en tablas. El bloqueo a
nivel de usuario, el comando "commit" hace que los cambios sean permanentes y elimina el
bloqueo. El comando "rollback" revierte los cambios antes de liberar el bloqueo. El programa
Oracle registra la información del bloqueo en una tabla del sistema, el cual se denomina
"v$lock" y lo podrás consultar usando el Lenguaje de consulta estructurado (SQL).
Paso 1
Revisa la tabla Oracle "v$lock" para bloquear la información. Utiliza la opción "Seleccionar"
para ver "sid", "type", "lmode" y "request". Sid representa el número ID de sesión e identifica
la sesión que posee el bloqueo.
Paso 2
Une la tabla Oracle "v$session" a la tabla "v$lock" para determinar quién está bloqueando la
base de datos. Une la sesión sid (sesión ID) para encontrar el nombre de usuario.
select s.username, s.sid, l.type, l.lmode, l.request from v$lock l, v$session s where l.sid = s.sid;
Paso 3
Consulta la tabla "v$locked_object" para obtener más información sobre lo que la está
bloqueando. Une la tabla "dba_objects" para el nombre y el tipo. El nombre del objeto indica
que está bloqueado y las columnas del nombre de usuario identifican a quién ha creado el
bloqueo.
SELECT
decode(L.TYPE,'TM','TABLE','TX','Record(s)') TYPE_LOCK,
decode(L.REQUEST,0,'NO','YES') WAIT,
S.OSUSER OSUSER_LOCKER,
S.PROCESS PROCESS_LOCKER,
S.USERNAME DBUSER_LOCKER,
O.OBJECT_NAME OBJECT_NAME,
O.OBJECT_TYPE OBJECT_TYPE,
concat(' ',s.PROGRAM) PROGRAM,
O.OWNER OWNER
FROM v$lock l,dba_objects o,v$session s
WHERE l.ID1 = o.OBJECT_ID
AND s.SID =l.SID
AND l.TYPE in ('TM','TX');
Muchas veces debido a la codificación de nuestras aplicaciones se presentan casos en los que
un segundo usuario se queda esperando mucho tiempo a que finalice una transacción porque
un primer usuario ya tiene bloqueada una o varias tablas que el segundo requiere.
FROM Dba_Locks
Con esta sentencia sabré el Id de la sesión que me está ocasionando un bloqueo. Pero quizás
quiera saber también quienes están esperando. Los resultado de esta consulta son algo así:
Me muestra que la sesión 69 está esperando a que la 171 libere algún recurso.
Sin embargo estos resultados me dicen poco, tendría que ingresar a ver las sesiones para
saber quiénes son estos usuarios y qué están haciendo, pero podemos mejorar el query
3. Qué recursos están usando quienes bloquean y esperan?
ORDER BY l.Id1;
En la columna Object_Name nos dice cuál es el recurso usado o esperado, como está
ordenado por el número de apariciones en el resultado, podemos saber cuáles son las que
están bloqueadas. El OSUSER es el usuario de sistema operativo y Machine el nombre del
equipo con el que el usuario se logueó, así podremos identificar mejor a los actores en este
asunto. Seconds_in_Wait me dice el tiempo que lleva esperando (el que está en espera) y la
última columna es simplemente la cuenta con la que estoy ordenando el resultado.
Una vez finalizada alguna de las dos sesiones en conflicto el resultado de los 3 querys debe
estar vacío.
Desde el punto de vista del usuario lo que verá será como la aplicación se cuelga por
completo y estará a la espera hasta que la primera sesión libere su bloqueo. A
menudo se tiene que identificar estas sesiones con el fin de mejorar su aplicación para
evitar el mayor número de sesiones de bloqueo posible.
Podemos encontrar las sesiones bloqueadas con el siguiente script el cual esta
buscando los objetos que empiecen con MTL.
Ahora si queremos matar una sesión de una de las tablas podemos realizar lo
siguiente:
DECLARE
CURSOR c IS
SELECT c.owner,
c.object_name,
c.object_type,
b.SID,
b.serial#,
b.status,
b.osuser,
b.machine
c_row c%ROWTYPE;
l_sql VARCHAR2(100);
BEGIN
OPEN c;
LOOP
END LOOP;
CLOSE c;
END;
Si falla terminar la sesión, debemos terminar la tarea desde una consola. Obtenemos el
SID con la siguiente consulta:
kill -9 58623