ORA-00054: recurso ocupado y adquirir con NOWAIT especificado o expirado el tiempo de espera


193

¿Por qué recibo este error de base de datos cuando actualizo una tabla?

ERROR en la línea 1: ORA-00054: recurso ocupado y adquisición con NOWAIT especificado o tiempo de espera expirado


22
En general, es útil si publica la declaración que conduce al error
Gary Myers

Respuestas:


222

Su tabla ya está bloqueada por alguna consulta. Por ejemplo, puede haber ejecutado "seleccionar para actualizar" y aún no haber confirmado / revertido y disparado otra consulta de selección. Haga un commit / rollback antes de ejecutar su consulta.


47
Agregaría 'en otra sesión' a eso. Un escenario común es que ha probado la actualización en una herramienta, por ejemplo, SQL Developer o Toad, y luego ha intentado ejecutarla en otro lugar mientras la primera sesión todavía mantiene el bloqueo. Por lo tanto, debe confirmar / revertir la otra sesión antes de poder ejecutar la actualización nuevamente.
Alex Poole

1
Lo más probable es DML (insertar / eliminar / actualizar) en lugar de una consulta. Y en otra sesión. Solo porque el chico que preguntó parece ser un novato, la respuesta puede ser correcta. Pero NO PUEDE comprometerse en nombre de otros usuarios en un sistema de producción.
Arturo Hernández

44
Bueno, lo que me hizo tener ese problema fue en Toad: un colega estaba en la misma tabla que yo cuando quería eliminar una fila, por lo que no pude eliminarla. Cuando cambió a otra tabla, pude eliminar filas. Tal vez ayude a alguien por ahí. Pero esto es solo si trabaja con Toad dentro de las tablas, y no para consultas.
DatRid

Ocurrió recientemente en nuestro servidor de ensayo (aplicación Spring en WebSphere). La solución fue separar el script de actualización de la base de datos "monolítico" en partes más pequeñas moviendo las declaraciones que causan errores a un servicio de actualización separado que usa una transacción separada: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

102

desde aquí ORA-00054: recurso ocupado y adquirir con NOWAIT especificado

También puede buscar la información de sql, nombre de usuario, máquina, puerto y acceder al proceso real que mantiene la conexión

SELECT O.OBJECT_NAME, S.SID, S.SERIAL#, P.SPID, S.PROGRAM,S.USERNAME,
S.MACHINE,S.PORT , S.LOGON_TIME,SQ.SQL_FULLTEXT 
FROM V$LOCKED_OBJECT L, DBA_OBJECTS O, V$SESSION S, 
V$PROCESS P, V$SQL SQ 
WHERE L.OBJECT_ID = O.OBJECT_ID 
AND L.SESSION_ID = S.SID AND S.PADDR = P.ADDR 
AND S.SQL_ADDRESS = SQ.ADDRESS;

55
Tuve que eliminar s.port de la consulta, pero me permitió encontrar al culpable
Sibster

Las cerraduras son transitorias. así que si viene el inserto, entonces se compromete de inmediato. no se mostrará en esta consulta. aún puede obtener el error si emite el 'DDL'. mientras la transacción está abierta. vea mi publicación a continuación. Esto es realmente fácil de solucionar.
Bob

44
Tengo el mismo problema que el OP, pero no puedo ver ninguna de las tablas que menciona (seleccione * de V $ LOCKED_OBJECT, por ejemplo, devuelve ORA-00942: la tabla o vista no existe). ¿Algunas ideas?
random_forest_fanatic

3
Es posible que no tenga los privilegios suficientes para mirar las vistas de administración.
njplumridge

Seguimiento del S.Portproblema: los documentos de 11.2 mencionan Portcomo un campo en V$Session, pero para mí, usar 11.1 S.Portno es válido. ¿Se agregó para 11.2, tal vez?

63

Por favor, mata la sesión de Oracle

Use la consulta a continuación para verificar la información de la sesión activa

SELECT
    O.OBJECT_NAME,
    S.SID,
    S.SERIAL#,
    P.SPID,
    S.PROGRAM,
    SQ.SQL_FULLTEXT,
    S.LOGON_TIME
FROM
    V$LOCKED_OBJECT L,
    DBA_OBJECTS O,
    V$SESSION S,
    V$PROCESS P,
    V$SQL SQ
WHERE
    L.OBJECT_ID = O.OBJECT_ID
    AND L.SESSION_ID = S.SID
    AND S.PADDR = P.ADDR
    AND S.SQL_ADDRESS = SQ.ADDRESS;

matar como

alter system kill session 'SID,SERIAL#';

(Por ejemplo alter system kill session '13,36543',;)

Referencia http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html


55
Debería advertir esta respuesta con qué privilegios se requieren. Tengo CONNECTy RESOURCE, pero no lo que sea que esto necesite, con la cuenta que tengo, y dice ORA-00942: table or view does not exist. No todos los que lean este hilo tendrán la SYScuenta.
vapcguy

Si agrega la columna de selección 'S.OSUSER' también sabrá qué usuario estaba ejecutando esa transacción y será útil en caso de que desee consultar con el usuario antes de finalizar la sesión.
Narasimha

Si se cuelga la sesión, alter system kill session '13,36543'se agota el tiempo de espera y la sesión no morirá. En ese caso, consulte: stackoverflow.com/a/24306610/587365
Andrew Spencer el

Mientras que la inserción de datos en una tabla mediante una connection objecten pythonTengo algunos errores. Luego python scriptse cierra sin cerrar correctamente el connection object. Ahora recibo el error "LOCKWAIT" cuando intento dejar la tabla en otra sesión. Cuando lo intento kill sessionno tengo suficiente privilegio. ¿Qué más se puede hacer para deshacerse de esto?
sjd

17

Hay una solución muy fácil para este problema.

Si ejecuta una traza 10046 en su sesión (google esto ... demasiado para explicar). Verá que antes de cualquier operación DDL, Oracle hace lo siguiente:

LOCK TABLE 'TABLE_NAME' SIN ESPERA

Entonces, si otra sesión tiene una transacción abierta, obtendrá un error. Entonces la solución es ... tambor por favor. Emita su propio bloqueo antes del DDL y omita el 'NO ESPERE'.

Nota especial:

si está haciendo partición / caída de particiones, Oracle simplemente bloquea la partición. - para que puedas bloquear la subpartición de partición.

Entonces ... Los siguientes pasos solucionan el problema.

  1. TABLA DE BLOQUEO 'NOMBRE DE LA TABLA'; - "Esperarás" (los desarrolladores llaman a esto colgar). hasta la sesión con la transacción abierta, confirma. Esta es una cola Por lo tanto, puede haber varias sesiones por delante. pero NO te equivocarás.
  2. Ejecute DDL. Su DDL ejecutará un bloqueo con NO WAIT. Sin embargo, su sesión ha adquirido el bloqueo. Entonces eres bueno.
  3. DDL auto-commits. Esto libera las cerraduras.

Las declaraciones DML 'esperarán' o como los desarrolladores lo llaman 'colgar' mientras la tabla está bloqueada.

Lo uso en el código que se ejecuta desde un trabajo para soltar particiones. Funciona bien. Está en una base de datos que se inserta constantemente a una velocidad de varios cientos de inserciones / segundo. Sin errores.

si te preguntas Haciendo esto en 11g. He hecho esto en 10 g antes también en el pasado.


3
Ok, esto está mal. en 11g, use set_ddl_timeout. Esto solo está disponible en 11g. Oracle realiza una confirmación antes de hacer DDL, por lo que libera el bloqueo. En 11g, puede hacer que su DDL espere. Estoy haciendo eso ahora. Funciona bien.
Bob

3
en 11g deberías usar LOCK TABLE table_name EN MODO EXCLUSIVO;
Kamil Roman

1
Esto es realmente útil si está obteniendo el ORA-00054 de trabajos por lotes, pero sospecho que la mayoría de las personas que aterrizan aquí (incluido el OP y yo) están desarrollando algo y han dejado una sesión abierta haciendo inserciones en la misma mesa que ' Estoy intentando soltar y recrear. KILL SESSIONes la respuesta correcta para estas personas.
Andrew Spencer

@Bob El código de ejemplo para 11g y para la forma anterior sería bueno. ¿Para qué es la sintaxis set_ddl_timeouty cuál debería ser?
vapcguy

1
@vapcguy esto funcionó para mí en 11g: ALTER SYSTEM SET ddl_lock_timeout=20;ver documentos
rshdev

13

Este error ocurre cuando el recurso está ocupado. Compruebe si tiene alguna restricción referencial en la consulta. O incluso las tablas que ha mencionado en la consulta pueden estar ocupadas. Es posible que se comprometan con algún otro trabajo que se enumerará definitivamente en los siguientes resultados de la consulta:

SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'

Encuentra el SID,

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id

1
No todos tendrán acceso a estas vistas. Consigo ORA-00942: table or view does not exist.
vapcguy

En tales casos, los administradores de DB son responsables de proporcionar esa información.
Arunchunaivendan

No siempre. Tuve que intentar que el código resolviera esto y lo solucionara, y ni yo ni mi cuenta de servicio tendremos estos derechos.
vapcguy

7

Esto sucede cuando una sesión distinta a la utilizada para alterar una tabla mantiene un bloqueo probablemente debido a un DML (actualizar / eliminar / insertar). Si está desarrollando un nuevo sistema, es probable que usted o alguien de su equipo emita la declaración de actualización y podría matar la sesión sin muchas consecuencias. O puede comprometerse desde esa sesión una vez que sepa quién tiene la sesión abierta.

Si tiene acceso a un sistema de administración SQL, úselo para encontrar la sesión ofensiva. Y tal vez matarlo.

Puede usar v $ session y v $ lock y otros, pero le sugiero que busque en Google cómo encontrar esa sesión y luego cómo matarla.

En un sistema de producción, realmente depende. Para Oracle 10g y anteriores, puede ejecutar

LOCK TABLE mytable in exclusive mode;
alter table mytable modify mycolumn varchar2(5);

En una sesión separada, pero tenga listo lo siguiente en caso de que tarde demasiado.

alter system kill session '....

Depende de qué sistema tenga, es más probable que los sistemas más antiguos no se comprometan cada vez. Eso es un problema ya que puede haber bloqueos de larga data. Por lo tanto, su bloqueo evitará cualquier bloqueo nuevo y esperará un bloqueo que quién sabe cuándo se liberará. Es por eso que tiene lista la otra declaración. O podría buscar scripts PLSQL que hagan cosas similares automáticamente.

En la versión 11g hay una nueva variable de entorno que establece un tiempo de espera. Creo que probablemente haga algo similar a lo que describí. Tenga en cuenta que los problemas de bloqueo no desaparecen.

ALTER SYSTEM SET ddl_lock_timeout=20;
alter table mytable modify mycolumn varchar2(5);

Finalmente, puede ser mejor esperar hasta que haya pocos usuarios en el sistema para realizar este tipo de mantenimiento.


¿Y cómo descubre la sesión para matar alter system kill session '....si no tiene acceso a las vistas de administración?
vapcguy

Eso no lo se.
Arturo Hernández

7

En mi caso, estaba bastante seguro de que era una de mis sesiones que estaba bloqueando. Por lo tanto, era seguro hacer lo siguiente:

  • Encontré la sesión ofensiva con:

    SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';

    La sesión estaba inactiva , pero aún mantenía el bloqueo de alguna manera. Tenga en cuenta que es posible que necesite usar alguna otra condición WHERE en su caso (por ejemplo, try USERNAMEo MACHINEfields).

  • Eliminó la sesión usando IDy SERIAL#adquirió lo anterior:

    alter system kill session '<id>, <serial#>';

Editado por @thermz: si ninguna de las consultas anteriores de sesión abierta funciona, prueba esta. Esta consulta puede ayudarlo a evitar errores de sintaxis al matar sesiones:

  • SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'

Si ninguna de las consultas de sesión abierta anteriores funciona, pruebe esta.
thermz

5

Simplemente verifique el proceso de celebración de la sesión y elimínelo. Ha vuelto a la normalidad.

Debajo de SQL encontrará su proceso

SELECT s.inst_id,
   s.sid,
   s.serial#,
   p.spid,
   s.username,
   s.program FROM   gv$session s
   JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id;

Entonces mátalo

ALTER SYSTEM KILL SESSION 'sid,serial#'

O

algún ejemplo que encontré en línea parece necesitar la identificación de la instancia, así como alterar la sesión de muerte del sistema '130,620, @ 1';



4

select
   c.owner,
   c.object_name,
   c.object_type,
   b.sid,
   b.serial#,
   b.status,
   b.osuser,
   b.machine
from
   v$locked_object a,
   v$session b,
   dba_objects c
where
   b.sid = a.session_id
and
   a.object_id = c.object_id;
   
   ALTER SYSTEM KILL SESSION 'sid,serial#';


3

¡Me las arreglé para dar con este error cuando simplemente creé una tabla! Obviamente, no había ningún problema de contención en una tabla que aún no existía. La CREATE TABLEdeclaración contenía una CONSTRAINT fk_name FOREIGN KEYcláusula que hacía referencia a una tabla bien poblada. Tuve que:

  • Elimine la cláusula FOREIGN KEY de la instrucción CREATE TABLE
  • Crear un ÍNDICE en la columna FK
  • Crea el FK

Acabo de tener el mismo problema. Pude crear la tabla después de eliminar la definición fk de la instrucción ddl, pero no puedo agregarla incluso después de crear el índice en la columna.
vadipp

Pude resolverlo. Primero, agregué una novalidatecláusula al alter table add constraint. Esto de alguna manera lo deja correr, pero se bloquea. Luego miré los bloqueos de sesión para averiguar en qué sesión se bloquea. Y luego maté esa sesión.
vadipp

3

Tuve este error cuando tuve 2 scripts que estaba ejecutando. Yo tenía:

  • Una sesión SQL * Plus conectada directamente usando una cuenta de usuario de esquema (cuenta # 1)
  • Otra sesión SQL * Plus conectada utilizando una cuenta de usuario de esquema diferente (cuenta # 2), pero conectando a través de un enlace de base de datos como la primera cuenta

Ejecuté una caída de la tabla, luego la creación de la tabla como cuenta # 1. Ejecuté una actualización de la tabla en la sesión de la cuenta # 2. No cometió cambios. Se volvió a ejecutar el script de creación / caída de la tabla como cuenta n. ° 1. Tengo un error en el drop table xcomando.

Lo resolví ejecutando COMMIT;en la sesión SQL * Plus de la cuenta # 2.


Si no tiene permisos para colocar una tabla, ¿qué hará? Mala respuesta
Shakeer Hussain

1
Shakeer, eso fue solo un ejemplo de lo que estaba haciendo cuando me sucedió a mí, no la solución al problema, que estaba en mi última línea: ejecutar a COMMIT;. Si ni siquiera puede soltar una tabla, no tiene los permisos para alterar nada que lo lleve a este problema en primer lugar.
vapcguy

-2

También me enfrento al problema similar. Nada programador tiene que hacer para resolver este error. Informé a mi equipo Oracle DBA. Matan la sesión y funcionan como un encanto.


1
Alguien todavía tiene que hacer algo. ¿Qué pasa si el equipo de DBA no sabe qué hacer y cómo matar una sesión? Mala respuesta.
vapcguy

1
Si el DBA no sabe cómo matar la sesión, entonces no está apto para trabajar
Shakeer Hussain,

Todos necesitan actualizar la sintaxis de vez en cuando para evitar equivocarse.
vapcguy

-5

La solución dada por el enlace de Shashi es la mejor ... no es necesario contactar a dba u otra persona

hacer una copia de seguridad

create table xxxx_backup as select * from xxxx;

eliminar todas las filas

delete from xxxx;
commit;

inserte su copia de seguridad.

insert into xxxx (select * from xxxx_backup);
commit;

10
eliminar / truncar no son intercambiables. realizar grandes cantidades de eliminaciones tiene implicaciones masivas de rendimiento. Esto es realmente malo
Bob

Pensé que este es un patrón común.
Shawn Xue
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.