217 votes

ORA-00054: ressource occupée et acquisition avec NOWAIT spécifié ou délai écoulé

Pourquoi ai-je cette erreur de base de données lorsque je mets à jour une table ?

ERREUR à la ligne 1 :
ORA-00054 : ressource occupée et acquisition avec spécification de NOWAIT ou expiration du délai

23 votes

Il est généralement utile si vous publiez l'énoncé qui provoque l'erreur

245voto

user258367 Points 630

Votre table est déjà verrouillée par une certaine requête. Par exemple, vous avez peut-être exécuté "select for update" et n'avez pas encore validé/annulé et avez lancé une autre requête select. Faites un commit/rollback avant d'exécuter votre requête.

55 votes

Je rajouterais 'dans une autre session' à ça. Un scénario courant est que vous avez testé la mise à jour dans un outil, disons SQL Developer ou Toad, et que vous avez ensuite essayé de l'exécuter ailleurs alors que la première session détient toujours le verrou. Vous devez donc valider/annuler l'autre session avant de pouvoir exécuter à nouveau la mise à jour.

2 votes

Il est très probable que ce soit une DML (insertion/suppression/mise à jour) plutôt qu'une requête. De plus, dans une autre session. Simplement parce que la personne qui demande semble être un débutant, la réponse peut être correcte. Mais vous ne pouvez PAS valider au nom d'autres utilisateurs dans un système de production.

4 votes

Eh bien, ce qui m'a causé ce problème était dans Toad : Un collègue était dans la même table que moi lorsque je voulais supprimer une ligne, et donc je ne pouvais pas la supprimer. Lorsqu'il est passé à une autre table, j'ai pu supprimer des lignes. Cela pourrait peut-être aider quelqu'un. Mais ceci est seulement si vous travaillez avec Toad à l'intérieur des tables, et pas pour les requêtes.

110voto

Abey Tom Points 276

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

Vous pouvez également rechercher les informations sql, nom d'utilisateur, machine, port et accéder au processus réel qui détient 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;

5 votes

J'ai dû enlever le s.port de la requête mais cela m'a permis de trouver le coupable.

0 votes

Les verrous sont transitoires. donc si l'insertion arrive, vous validez immédiatement. cela ne s'affichera pas dans cette requête. vous pouvez encore rencontrer l'erreur si vous émettez le 'DDL'. pendant que la transaction est ouverte. consultez mon message ci-dessous. C'est vraiment facile à contourner.

4 votes

Je rencontre le même problème que l'OP, mais je ne vois pas la table dont vous parlez (par exemple, select * from V$LOCKED_OBJECT renvoie ORA-00942 : table ou vue n'existe pas). Des idées ?

72voto

Chan Myae Thu Points 44

Veuillez tuer la session Oracle

Utilisez la requête ci-dessous pour vérifier les informations des sessions actives

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 la session comme suit

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

5 votes

Devrait préciser cette réponse par les privilèges nécessaires. J'ai CONNECT et RESOURCE, mais pas ce dont cela a besoin, avec le compte que j'ai, et dit ORA-00942: table ou vue n'existe pas. Tout le monde lisant ce fil n'aura pas le compte SYS.

0 votes

Si vous ajoutez la colonne de sélection 'S.OSUSER', vous saurez également quel utilisateur exécutait cette transaction et ce sera pratique si vous voulez vérifier avec l'utilisateur avant de tuer la session.

0 votes

Si la session est suspendue, alors alter system kill session '13,36543' expirera et la session ne mourra pas. Dans ce cas, voir: stackoverflow.com/a/24306610/587365

16voto

Bob Points 543

Il existe une solution très facile à ce problème.

Si vous exécutez une trace 10046 sur votre session (recherchez sur Google pour plus d'informations... trop long à expliquer). Vous verrez qu'avant toute opération DDL, Oracle effectue les étapes suivantes:

LOCK TABLE 'TABLE_NAME' NO WAIT

Donc, si une autre session a une transaction ouverte, vous obtenez une erreur. La solution est donc... roulement de tambour. Bloquez votre propre verrou avant le DDL et supprimez le 'NO WAIT'.

Note spéciale:

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

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

  1. LOCK TABLE 'NOM_TABLE'; -- vous 'attendez' (les développeurs appellent cela un blocage) jusqu'à ce que la session avec la transaction ouverte valide. Il s'agit d'une file d'attente. donc il peut y avoir plusieurs sessions devant vous. mais vous n'aurez PAS d'erreur.
  2. Exécutez le DDL. Votre DDL effectuera ensuite un verrou avec le NO WAIT. Cependant, votre session a acquis le verrou. Vous êtes donc bon.
  3. DDL s'auto-commit. Cela libère les verrous.

Les instructions DML 'attendent' ou, comme les développeurs l'appellent, 'bloquent' tant que la table est verrouillée.

Je fais cela dans du code qui s'exécute à partir d'une tâche pour supprimer des partitions. Cela fonctionne bien. C'est dans une base de données qui insère constamment à un rythme de plusieurs centaines d'insertions par seconde. Aucune erreur.

Si vous vous posez la question. J'ai fait cela en 11g. Je l'ai également fait en 10g dans le passé.

4 votes

Ok, ce n'est pas correct. en 11g, utilisez set_ddl_timeout, C'est seulement disponible en 11g. oracle effectue un commit avant de faire du DDL, donc il libère le verrou. En 11g, vous pouvez faire attendre votre DDL. Je le fais maintenant. Fonctionne bien.

4 votes

En 11g, vous devriez utiliser LOCK TABLE table_name IN EXCLUSIVE MODE;

1 votes

Ceci est vraiment utile si vous obtenez l'ORA-00054 à partir des jobs de lot, mais je soupçonne que la plupart des personnes atterrissant ici (y compris l'OP, et moi) font du développement et ont laissé une session ouverte effectuant des insertions sur la même table qu'ils essaient de supprimer et recréer. KILL SESSION est la bonne réponse pour ces personnes.

14voto

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. Elles pourraient être engagées dans un autre travail qui sera certainement 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 = --l'identifiant

1 votes

Tout le monde n'aura pas accès à ces vues. Je reçois ORA-00942: table ou vue n'existe pas.

0 votes

Dans de tels cas, les administrateurs de base de données sont responsables de fournir ces informations.

0 votes

Pas toujours. J'ai dû essayer de faire en sorte que le code puisse résoudre cela et le contourner, et ni moi ni mon compte de service n'aurons ces droits.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X