ORA-00054: Ressource belegt und mit NOWAIT angegeben oder Timeout abgelaufen


193

Warum wird dieser Datenbankfehler angezeigt, wenn ich eine Tabelle aktualisiere?

FEHLER in Zeile 1: ORA-00054: Ressource belegt und mit NOWAIT angegeben oder Timeout abgelaufen


22
Es ist im Allgemeinen hilfreich, wenn Sie die Erklärung veröffentlichen, die zum Fehler führt
Gary Myers

Antworten:


222

Ihre Tabelle ist bereits durch eine Abfrage gesperrt. Beispielsweise haben Sie möglicherweise "Zur Aktualisierung auswählen" ausgeführt und noch keine Festschreibungsabfrage festgeschrieben / zurückgesetzt und ausgelöst. Führen Sie ein Commit / Rollback durch, bevor Sie Ihre Abfrage ausführen.


47
Ich würde 'in einer anderen Sitzung' hinzufügen. Ein häufiges Szenario ist, dass Sie das Update in einem Tool getestet haben, z. B. SQL Developer oder Toad, und dann versucht haben, es an einer anderen Stelle auszuführen, während die erste Sitzung noch die Sperre hält. Sie müssen also die andere Sitzung festschreiben / zurücksetzen, bevor Sie das Update erneut ausführen können.
Alex Poole

1
Höchstwahrscheinlich DML (Einfügen / Löschen / Aktualisieren) anstelle einer Abfrage. Und in einer anderen Sitzung. Nur weil der Typ, der gefragt hat, ein Neuling zu sein scheint, kann die Antwort richtig sein. Sie können sich jedoch NICHT für andere Benutzer in einem Produktionssystem festlegen.
Arturo Hernandez

4
Nun, was mich zu diesem Problem gebracht hat, war Toad: Ein Kollege befand sich in derselben Tabelle wie damals, als ich eine Zeile löschen wollte, und konnte sie daher nicht löschen. Als er zu einer anderen Tabelle wechselte, konnte ich Zeilen löschen. Es hilft vielleicht jemandem da draußen. Dies ist jedoch nur möglich, wenn Sie mit Toad in den Tabellen arbeiten, und nicht für Abfragen.
DatRid

Vor kurzem auf unserem Staging-Server (Spring-Anwendung auf WebSphere) aufgetreten. Die Lösung bestand darin, das "monolithische" Datenbankaktualisierungsskript in kleinere Teile zu trennen, indem die fehlerverursachenden Anweisungen in einen separaten Aktualisierungsdienst verschoben wurden, der eine separate Transaktion verwendet: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

102

von hier ORA-00054: Ressource belegt und mit NOWAIT angegeben erwerben

Sie können auch die SQL-, Benutzernamen-, Computer- und Portinformationen nachschlagen und zum eigentlichen Prozess gelangen, der die Verbindung enthält

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
Ich musste s.port aus der Abfrage entfernen, aber es ließ mich den Täter finden
Sibster

Schlösser sind vorübergehend. Wenn also die Beilage kommt, verpflichten Sie sich sofort. Es wird in dieser Abfrage nicht angezeigt. Sie können den Fehler immer noch erhalten, wenn Sie die 'DDL' ausgeben. während die Transaktion geöffnet ist. siehe meinen Beitrag unten. Dies ist wirklich einfach zu umgehen.
Bob

4
Ich habe das gleiche Problem wie das OP, aber ich kann keine der von Ihnen erwähnten Tabellen sehen (wählen Sie * aus V $ LOCKED_OBJECT aus, z. B. gibt ORA-00942 zurück: Tabelle oder Ansicht existiert nicht). Irgendwelche Ideen?
random_forest_fanatic

3
Möglicherweise verfügen Sie nicht über ausreichende Berechtigungen, um die Verwaltungsansichten anzuzeigen.
NJPLUMRAT

Follow-up zum S.PortProblem: Die 11.2-Dokumente erwähnen Portals Feld in V$Session, aber für mich ist die Verwendung von 11.1 S.Portungültig. Wurde es vielleicht für 11.2 hinzugefügt?

63

Bitte beenden Sie die Oracle-Sitzung

Verwenden Sie die folgende Abfrage, um die aktiven Sitzungsinformationen zu überprüfen

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;

töte wie

alter system kill session 'SID,SERIAL#';

(Zum Beispiel alter system kill session '13,36543';)

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


5
Sollte diese Antwort mit den erforderlichen Berechtigungen einschränken. Ich habe CONNECTund RESOURCE, aber nicht was auch immer dies braucht, mit dem Konto, das ich habe, und sagt ORA-00942: table or view does not exist. Nicht jeder, der diesen Thread liest, hat den SYSAccount.
Vapcguy

Wenn Sie auch die Auswahlspalte 'S.OSUSER' hinzufügen, wissen Sie, welcher Benutzer diese Transaktion ausgeführt hat, und dies ist hilfreich, wenn Sie sich vor dem Beenden der Sitzung beim Benutzer erkundigen möchten.
Narasimha

Wenn die Sitzung unterbrochen wird, tritt alter system kill session '13,36543'eine Zeitüberschreitung auf und die Sitzung wird nicht beendet. In diesem Fall siehe: stackoverflow.com/a/24306610/587365
Andrew Spencer

Beim Einfügen von Daten in eine Tabelle mit einem connection objectin habe pythonich einen Fehler erhalten. Dann wird das python scriptgeschlossen, ohne das richtig zu schließen connection object. Jetzt erhalte ich den Fehler "LOCKWAIT", wenn ich versuche, die Tabelle in einer anderen Sitzung zu löschen. Wenn ich es versuche, habe kill sessionich nicht genug Privilegien. Was kann man noch tun, um dies loszuwerden?
Sjd

17

Es gibt eine sehr einfache Lösung für dieses Problem.

Wenn Sie in Ihrer Sitzung einen 10046-Trace ausführen (googeln Sie dies ... zu viel, um es zu erklären). Sie werden sehen, dass Oracle vor jeder DDL-Operation Folgendes ausführt:

LOCK TABLE 'TABLE_NAME' KEINE WARTUNG

Wenn also eine andere Sitzung eine offene Transaktion hat, wird eine Fehlermeldung angezeigt. Das Problem ist also ... Trommelwirbel bitte. Stellen Sie Ihre eigene Sperre vor der DDL aus und lassen Sie das 'NO WAIT' weg.

Spezielle Notiz:

Wenn Sie Partitionen teilen / löschen, sperrt Oracle die Partition einfach. - Sie können also einfach die Partitionsunterpartition sperren.

Also ... Die folgenden Schritte beheben das Problem.

  1. LOCK TABLE 'TABLE NAME'; - Sie werden warten (Entwickler nennen dies hängen). bis die Sitzung mit der offenen Transaktion festschreibt. Dies ist eine Warteschlange. Es können also mehrere Sitzungen vor Ihnen liegen. aber Sie werden NICHT Fehler aus.
  2. Führen Sie DDL aus. Ihre DDL führt dann eine Sperre mit NO WAIT aus. Ihre Sitzung hat jedoch die Sperre erhalten. Du bist also gut.
  3. DDL-Commits automatisch. Dies befreit die Schlösser.

DML-Anweisungen warten, oder wie Entwickler sie als "hängen" bezeichnen, während die Tabelle gesperrt ist.

Ich verwende dies in Code, der von einem Job ausgeführt wird, um Partitionen zu löschen. Es funktioniert gut. Es befindet sich in einer Datenbank, die ständig mit einer Geschwindigkeit von mehreren hundert Einfügungen / Sekunde eingefügt wird. Keine Fehler.

wenn Sie sich fragen. Tun Sie dies in 11g. Ich habe dies auch schon in der Vergangenheit in 10 g gemacht.


3
ok das ist falsch Verwenden Sie in 11g das set_ddl_timeout. Dies ist nur in 11g verfügbar. oracle führt vor dem Ausführen von DDL ein Commit durch, sodass die Sperre aufgehoben wird. In 11g können Sie Ihre DDL warten lassen. Das mache ich jetzt. Funktioniert gut.
Bob

3
In 11g sollten Sie LOCK TABLE table_name IN EXCLUSIVE MODE verwenden.
Kamil Roman

1
Dies ist sehr nützlich, wenn Sie den ORA-00054 aus Batch-Jobs beziehen, aber ich vermute, dass die meisten Leute, die hier landen (einschließlich des OP und mir), einige Entwicklungsarbeiten durchführen und eine Sitzung offen gelassen haben, in der Einfügungen an derselben Tabelle vorgenommen werden, an der sie sich befinden. Ich versuche zu löschen und neu zu erstellen. KILL SESSIONist die richtige Antwort für diese Leute.
Andrew Spencer

@ Bob Beispielcode für 11g und den alten Weg wäre schön. Wofür ist die Syntax set_ddl_timeoutund was soll sie sein?
Vapcguy

1
@vapcguy das hat bei mir auf 11g funktioniert: ALTER SYSTEM SET ddl_lock_timeout=20;siehe docs
rshdev

13

Dieser Fehler tritt auf, wenn die Ressource ausgelastet ist. Überprüfen Sie, ob die Abfrage referenzielle Einschränkungen enthält. Oder sogar die Tabellen, die Sie in der Abfrage erwähnt haben, sind möglicherweise ausgelastet. Sie sind möglicherweise mit einem anderen Job beschäftigt, der in den folgenden Abfrageergebnissen definitiv aufgeführt wird:

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

Finden Sie die SID,

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

1
Nicht jeder hat Zugriff auf diese Ansichten. Ich verstehe ORA-00942: table or view does not exist.
Vapcguy

In solchen Fällen sind DB-Administratoren für die Bereitstellung dieser Informationen verantwortlich.
Arunchunaivendan

Nicht immer. Ich musste versuchen, dass Code dies herausfindet und umgeht, und weder ich noch mein Dienstkonto haben diese Rechte.
Vapcguy

7

Dies geschieht, wenn eine andere Sitzung als die zum Ändern einer Tabelle verwendete eine Sperre enthält, die wahrscheinlich auf eine DML zurückzuführen ist (Aktualisieren / Löschen / Einfügen). Wenn Sie ein neues System entwickeln, ist es wahrscheinlich, dass Sie oder jemand in Ihrem Team die Update-Anweisung herausgibt und Sie die Sitzung ohne große Konsequenzen beenden können. Oder Sie können sich aus dieser Sitzung verpflichten, sobald Sie wissen, wer die Sitzung geöffnet hat.

Wenn Sie Zugriff auf ein SQL-Administrationssystem haben, verwenden Sie es, um die fehlerhafte Sitzung zu finden. Und vielleicht töte es.

Sie könnten v $ session und v $ lock und andere verwenden, aber ich schlage vor, Sie googeln, wie Sie diese Sitzung finden und dann beenden.

In einem Produktionssystem kommt es wirklich darauf an. Für Oracle 10g und älter können Sie ausführen

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

Halten Sie in einer separaten Sitzung Folgendes bereit, falls es zu lange dauert.

alter system kill session '....

Es hängt davon ab, über welches System Sie verfügen. Ältere Systeme werden mit größerer Wahrscheinlichkeit nicht jedes Mal festgeschrieben. Dies ist ein Problem, da möglicherweise lange Schlösser vorhanden sind. Ihr Schloss würde also neue Sperren verhindern und auf ein Schloss warten, das weiß, wann es freigegeben wird. Deshalb haben Sie die andere Aussage bereit. Oder Sie könnten nach PLSQL-Skripten suchen, die ähnliche Dinge automatisch ausführen.

In Version 11g gibt es eine neue Umgebungsvariable, die eine Wartezeit festlegt. Ich denke, es macht wahrscheinlich etwas Ähnliches wie das, was ich beschrieben habe. Wohlgemerkt, dass Sperrprobleme nicht verschwinden.

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

Schließlich kann es am besten sein, zu warten, bis sich nur noch wenige Benutzer im System befinden, um diese Art der Wartung durchzuführen.


Und wie finden Sie heraus, für welche Sitzung Sie die Sitzung beenden müssen, alter system kill session '....wenn Sie keinen Zugriff auf die Verwaltungsansichten haben?
Vapcguy

Das weiß ich nicht.
Arturo Hernandez

7

In meinem Fall war ich mir ziemlich sicher, dass es eine meiner eigenen Sitzungen war, die blockierte. Daher war es sicher, Folgendes zu tun:

  • Ich fand die beleidigende Sitzung mit:

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

    Die Sitzung war inaktiv , hielt aber irgendwie die Sperre. Beachten Sie, dass Sie in Ihrem Fall möglicherweise eine andere WHERE- Bedingung verwenden müssen (z. B. try USERNAMEoder MACHINEFelder).

  • Tötete die Sitzung mit dem IDund SERIAL#erworben oben:

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

Bearbeitet von @thermz: Wenn keine der vorherigen Open-Session-Abfragen funktioniert, versuchen Sie diese. Diese Abfrage kann Ihnen helfen, Syntaxfehler beim Beenden von Sitzungen zu vermeiden:

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

Wenn keine der vorherigen Open-Session-Abfragen funktioniert, versuchen Sie diese.
Thermz

5

Überprüfen Sie einfach, ob die Sitzung gehalten wird, und beenden Sie sie. Es ist wieder normal.

Unter SQL finden Sie Ihren Prozess

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;

Dann töte es

ALTER SYSTEM KILL SESSION 'sid,serial#'

ODER

Ein Beispiel, das ich online gefunden habe, scheint auch die Instanz-ID zu benötigen, um die System-Kill-Sitzung '130,620, @ 1' zu ändern.



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

Ich habe diesen Fehler beim einfachen Erstellen einer Tabelle festgestellt! Es gab offensichtlich kein Konfliktproblem auf einem Tisch, der noch nicht existierte. Die CREATE TABLEAnweisung enthielt eine CONSTRAINT fk_name FOREIGN KEYKlausel, die auf eine gut ausgefüllte Tabelle verweist. Ich musste:

  • Entfernen Sie die FOREIGN KEY-Klausel aus der Anweisung CREATE TABLE
  • Erstellen Sie einen INDEX in der Spalte FK
  • Erstellen Sie die FK

Ich hatte gerade das gleiche Problem. Ich konnte die Tabelle erstellen, nachdem ich die fk-Definition aus der ddl-Anweisung entfernt hatte, aber ich kann sie auch nach dem Erstellen des Index für die Spalte nicht hinzufügen.
Vadipp

Ich konnte es lösen. Zuerst habe ich dem eine novalidateKlausel hinzugefügt alter table add constraint. Das lässt es irgendwie laufen, aber es sperrt. Dann habe ich mir die Sitzungssperren angesehen, um herauszufinden, für welche Sitzung sie gesperrt sind. Und dann habe ich diese Sitzung beendet.
Vadipp

3

Ich hatte diesen Fehler, als ich 2 Skripte hatte, die ich ausführte. Ich hatte:

  • Eine SQL * Plus-Sitzung, die direkt über ein Schema-Benutzerkonto (Konto 1) verbunden ist.
  • Eine andere SQL * Plus-Sitzung, die über ein anderes Schema-Benutzerkonto (Konto Nr. 2) verbunden ist, jedoch als erstes Konto eine Verbindung über eine Datenbankverbindung herstellt

Ich habe eine Tabellenablage ausgeführt und dann die Tabellenerstellung als Konto Nr. 1. Ich habe ein Tabellen-Update für die Sitzung von Konto 2 ausgeführt. Keine Änderungen vorgenommen. Skript zum Löschen / Erstellen von Tabellen als Konto Nr. 1 erneut ausgeführt. Fehler beim drop table xBefehl.

Ich habe es gelöst, indem ich COMMIT;in der SQL * Plus-Sitzung von Konto 2 ausgeführt habe.


Wenn Sie keine Berechtigung zum Löschen einer Tabelle haben, was werden Sie dann tun? Schlechte Antwort
Shakeer Hussain

1
Shakeer, das war nur ein Beispiel dafür, was ich tat, als es mir passierte - nicht die Lösung des Problems - das war in meiner allerletzten Zeile - a COMMIT;. Wenn Sie nicht einmal eine Tabelle löschen können, haben Sie nicht die Berechtigung, etwas zu ändern, das Sie überhaupt in dieses Problem bringen würde.
Vapcguy

-2

Ich stehe auch vor dem ähnlichen Problem. Der Programmierer muss nichts tun, um diesen Fehler zu beheben. Ich informierte mein Orakel-DBA-Team. Sie haben die Sitzung beendet und wie ein Zauber gearbeitet.


1
Jemand muss noch etwas tun. Was ist, wenn das DBA-Team nicht weiß, was zu tun ist und wie eine Sitzung beendet werden soll? Falsche Antwort.
Vapcguy

1
Wenn DBA nicht weiß, wie man eine Sitzung beendet, ist er nicht arbeitsfähig
Shakeer Hussain

Jeder braucht von Zeit zu Zeit eine Auffrischung der Syntax, um Fehler zu vermeiden.
Vapcguy

-5

Die von Shashis Link gegebene Lösung ist die beste ... Sie müssen sich nicht an dba oder eine andere Person wenden

Erstelle eine Sicherung

create table xxxx_backup as select * from xxxx;

Alle Zeilen löschen

delete from xxxx;
commit;

Fügen Sie Ihr Backup ein.

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

10
Löschen / Abschneiden sind nicht austauschbar. Das Durchführen einer großen Anzahl von Löschvorgängen hat massive Auswirkungen auf die Leistung. Das ist wirklich schlimm.
Bob

Ich dachte, das ist ein allgemeines Muster.
Shawn Xue
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.