web-dev-qa-db-fra.com

ORA-00054: ressource occupée et acquise avec NOWAIT spécifiée ou délai d'attente expiré

Pourquoi est-ce que je reçois cette erreur de base de données lorsque je mets à jour une table?

ERREUR à la ligne 1: ORA-00054: ressource occupée et acquise avec NOWAIT spécifié ou expiration du délai d'attente

165
sun

Votre table est déjà verrouillée par une requête. Par exemple, vous avez peut-être exécuté "sélectionner pour la mise à jour" et n'avez pas encore validé/annulé et déclenché une autre requête de sélection. Effectuez une validation/annulation avant d'exécuter votre requête.

194
user258367

à partir d'ici ORA-00054: ressource occupée et acquise avec NOWAIT spécifié

Vous pouvez également rechercher les informations SQL, nom d'utilisateur, machine, informations de port et accéder au processus qui contient la connexion.

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;
89
Abey Tom

S'il vous plaît tuer Oracle session

Utilisez la requête ci-dessous pour vérifier les informations de la session active

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;

tuer comme

alter system kill session 'SID,SERIAL#';

(Par exemple, alter system kill session '13,36543';)

Référence http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html

53
Chan Myae Thu

Il existe un moyen très facile de contourner ce problème.

Si vous exécutez une trace 10046 sur votre session (google ceci ... trop à expliquer). Vous verrez cela avant toute opération DDL, Oracle procède comme suit:

LOCK TABLE 'TABLE_NAME' PAS D'ATTENTE

Donc, si une autre session a une transaction ouverte, vous obtenez une erreur. Donc, la solution est ... roulement de tambour s'il vous plaît. Émettez votre propre verrou avant le DDL et omettez le "NO WAIT".

Note spéciale:

si vous divisez/supprimez des partitions, Oracle verrouille simplement la partition. - Vous pouvez donc simplement verrouiller la sous-partition de la partition.

Alors ... Les étapes suivantes résolvent le problème.

  1. LOCK TABLE 'NOM DE LA TABLE'; - vous allez "attendre" (les développeurs appellent cela suspendu). jusqu'à la session avec la transaction ouverte, valide. Ceci est une file d'attente. il peut donc y avoir plusieurs sessions devant vous. mais vous ne ferez pas d'erreur.
  2. Exécutez DDL. Votre DDL exécutera alors un verrou avec NO WAIT. Cependant, votre session a acquis le verrou. Donc tu es bon.
  3. DDL se commet automatiquement. Cela libère les serrures.

Les instructions DML "patienteront" ou, comme les développeurs l’appelleront "se bloquer" tant que la table sera verrouillée.

J'utilise ceci dans le code qui s'exécute à partir d'un travail pour supprimer des partitions. Ça fonctionne bien. C'est dans une base de données qui insère constamment à une vitesse de plusieurs centaines d'inserts/seconde. Aucune erreur.

si vous vous demandez. Faire cela en 11g. Je l'ai déjà fait dans 10g auparavant.

16
Bob

Cette erreur se produit lorsque la ressource est occupée. Vérifiez si vous avez des contraintes référentielles dans la requête. Ou même les tables que vous avez mentionnées dans la requête peuvent être occupées. Ils pourraient être engagés avec un autre travail qui sera définitivement répertorié dans les résultats de la requête suivante:

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

Trouvez le SID,

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

Dans mon cas, j'étais à peu près sûr que c'était l'une des mes propres sessions qui bloquait. Par conséquent, il était prudent de procéder comme suit:

  • J'ai trouvé la session incriminée avec:

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

    La session était inactive, mais le verrou était toujours bloqué. Notez que vous devrez peut-être utiliser une autre condition dans votre cas (par exemple, essayez USERNAME ou MACHINE champs ).

  • Tué la session en utilisant les ID et SERIAL# acquis ci-dessus:

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

Edité par @thermz: Si aucune des requêtes précédentes à session ouverte ne fonctionne, essayez celle-ci. Cette requête peut vous aider à éviter les erreurs de syntaxe lors de la suppression de sessions:

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

Cela se produit lorsqu'une session autre que celle utilisée pour modifier une table détient un verrou, probablement à cause d'un DML (update/delete/insert). Si vous développez un nouveau système, il est probable que vous, ou un membre de votre équipe, émettez la déclaration de mise à jour et que vous puissiez tuer la session sans trop de conséquences. Ou vous pouvez vous engager à partir de cette session une fois que vous savez qui a ouvert la session.

Si vous avez accès à un système administrateur SQL, utilisez-le pour rechercher la session incriminée. Et peut-être le tuer.

Vous pouvez utiliser v $ session et v $ lock et autres, mais je vous suggère de rechercher sur Google la session puis de la tuer.

Dans un système de production, cela dépend vraiment. Pour Oracle 10g et plus ancien, vous pouvez exécuter

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

Dans une session séparée, mais ayez ce qui suit prêt au cas où cela prendrait trop de temps.

alter system kill session '....

Cela dépend de votre système. Les systèmes plus anciens sont plus susceptibles de ne pas s’engager à chaque fois. C'est un problème car il peut y avoir des serrures de longue date. Ainsi, votre verrou empêchera tout nouveau verrou et attendra un verrou qui sait quand sera publié. C'est pourquoi vous avez préparé l'autre déclaration. Vous pouvez également rechercher des scripts PLSQL qui effectuent des opérations similaires automatiquement.

Dans la version 11g, une nouvelle variable d’environnement définit un temps d’attente. Je pense que cela fait probablement quelque chose de similaire à ce que j'ai décrit. Notez que les problèmes de verrouillage ne disparaissent pas.

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

Enfin, il peut être préférable d’attendre que le système compte peu d’utilisateurs pour effectuer ce type de maintenance.

6
Arturo Hernandez

Votre problème semble indiquer que vous mélangez des opérations DML et DDL. Voir cette URL qui explique ce problème:

http://www.orafaq.com/forum/t/54714/2/

4
Shashi

Il suffit de vérifier le processus de tenue de la session et de le tuer. Son retour à la normale.

Ci-dessous, SQL trouvera votre processus

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;

Puis tuez-le

ALTER SYSTEM KILL SESSION 'sid,serial#'

OR

certains exemples que j'ai trouvés en ligne semblent avoir besoin de l'identifiant d'instance ainsi que de modifier la session de destruction du système '130,620, @ 1';

4
Mathavan John

J'ai réussi à frapper cette erreur en créant simplement une table! Il n'y avait évidemment aucun problème de conflit sur une table qui n'existait pas encore. L'instruction CREATE TABLE contenait une clause CONSTRAINT fk_name FOREIGN KEY faisant référence à une table bien remplie. J'ai dû:

  • Supprimez la clause FOREIGN KEY de l'instruction CREATE TABLE.
  • Créer un INDEX sur la colonne FK
  • Créer le FK
3
bwperrin

J'ai eu cette erreur se produire lorsque j'avais 2 scripts que je courais. J'avais:

  • Une session SQL * Plus connectée directement à l'aide d'un compte utilisateur de schéma (compte n ° 1)
  • Une autre session SQL * Plus connectée à l'aide d'un compte d'utilisateur de schéma différent (compte n ° 2), mais se connectant via un lien de base de données en tant que premier compte

J'ai couru un dépôt de table, puis la création de table en tant que compte n ° 1. J'ai exécuté une mise à jour de table sur la session du compte n ° 2. N'a pas commis de changements. Le script de création/suppression de table a été relancé en tant que compte n ° 1. Vous avez une erreur sur la commande drop table x.

Je l'ai résolu en exécutant COMMIT; dans la session SQL * Plus du compte n ° 2.

3
vapcguy