ORA-00054:リソースがビジーで、NOWAITを指定して取得するか、タイムアウトの期限が切れました


193

テーブルを更新すると、このデータベースエラーが発生するのはなぜですか?

1行目のエラー:ORA-00054:リソースがビジーで、NOWAITを指定して取得するか、タイムアウトの期限が切れました


22
エラーにつながるステートメントを投稿すると、一般的に役立ちます
Gary Myers

回答:


222

テーブルは既にいくつかのクエリによってロックされています。たとえば、「select for update」を実行し、まだコミット/ロールバックしておらず、別の選択クエリを実行していない可能性があります。クエリを実行する前に、コミット/ロールバックを実行します。


47
これに「別のセッションで」を追加します。一般的なシナリオの1つは、SQL DeveloperまたはToadなどのツールで更新をテストし、最初のセッションがまだロックを保持している間に別の場所で実行しようとした場合です。したがって、更新を再度実行する前に、他のセッションをコミット/ロールバックする必要があります。
Alex Poole 2011年

1
おそらくクエリではなくDML(挿入/削除/更新)。そして別のセッションで。質問した人が初心者のようであるという理由だけで、答えは正しいかもしれません。ただし、本番システムで他のユーザーに代わってコミットすることはできません。
Arturo Hernandez

4
さて、私がその問題を抱えたのはToadにありました。同僚が行を削除したいときと同じテーブルにいて、行を削除できませんでした。彼が別のテーブルに切り替えたとき、行を削除することができました。それは多分誰かを助けるでしょう。しかし、これはテーブル内でToadを操作する場合にのみ当てはまり、クエリではありません。
DatRid 2013年

最近、ステージングサーバー(WebSphere上のSpringアプリケーション)で発生しました。@Transactional(伝播= Propagation.REQUIRES_NEW):溶液を、別のトランザクションを使用する別の更新サービスにエラーの原因となる文を移動させることにより小片に「モノリシック」データベース更新スクリプトを分離することであった
ACTC

102

ここからORA-00054:リソースはビジーで、NOWAITを指定して取得します

また、sql、username、machine、port情報を検索して、接続を保持する実際のプロセスを取得することもできます

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
クエリからs.portを削除する必要がありましたが、原因を
特定

ロックは一時的です。したがって、挿入が発生した場合は、すぐにコミットします。このクエリには表示されません。「DDL」を発行すると、エラーが発生する可能性があります。トランザクションが開いている間。以下の私の投稿を参照してください。これは非常に簡単に回避できます。
ボブは

4
OPと同じ問題が発生していますが、言及しているテーブルがどれも表示されません(たとえば、*をV $ LOCKED_OBJECTから選択すると、ORA-00942が返されます:テーブルまたはビューが存在しません)。何か案は?
random_forest_fanatic 2013

3
管理ビューを表示するための十分な権限がない可能性があります。
njplumridge 2013

S.Port問題のフォローアップ:11.2のドキュメントではPortのフィールドとして言及していますV$Sessionが、私にとって11.1の使用S.Portは無効です。11.2で追加されたのでしょうか?

63

Oracleセッションを強制終了してください

以下のクエリを使用してアクティブなセッション情報を確認してください

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;

のように殺す

alter system kill session 'SID,SERIAL#';

(たとえば、alter system kill session '13,36543';)

リファレンス http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html


5
どのような権限が必要かについて、この回答を警告する必要があります。私が持っているCONNECTRESOURCE私が持っている、と述べているアカウントで、何でもこのニーズを、ではなくORA-00942: table or view does not exist。このスレッドを読んでいる全員がSYSアカウントを持つわけではありません。
vapcguy

選択列「S.OSUSER」も追加すると、どのユーザーがそのトランザクションを実行していたかがわかり、セッションを終了する前にユーザーに確認したい場合に便利です。
ナラシンハ

セッションがハングしている場合、alter system kill session '13,36543'タイムアウトし、セッションは停止しません。その場合は、次を参照してください。stackoverflow.com
Andrew Spencer

connection objectin を使用してテーブルにデータを挿入すると、pythonエラーが発生しました。次に、python scriptを適切に閉じずにを閉じますconnection object。別のセッションでテーブルを削除しようとすると、「LOCKWAIT」エラーが発生します。試してみると、kill session十分な特権がありません。これを取り除くために他に何ができますか?
sjd

17

この問題の回避策は非常に簡単です。

セッションで10046トレースを実行した場合(google this ...説明が多すぎます)。DDL操作の前にOracleが次のことを行うことがわかります。

テーブル 'TABLE_NAME'をロックしてください

したがって、別のセッションで開いているトランザクションがある場合、エラーが発生します。だから修正は...ドラムロールをお願いします。DDLの前に独自のロックを発行し、「NO WAIT」を省略します。

特記事項:

パーティションを分割/削除する場合、Oracleはパーティションをロックするだけです。-つまり、パーティションサブパーティションをロックするだけです。

次の手順で問題を解決します。

  1. ロックテーブル 'テーブル名'; -あなたは「待つ」ことになります(開発者はこれをぶら下げと呼んでいます)。開いているトランザクションのセッションがコミットされるまで。これはキューです。あなたの前にいくつかのセッションがあるかもしれません。エラーは発生しません。
  2. DDLを実行します。DDLはNO WAITでロックを実行します。ただし、セッションがロックを取得しました。だからあなたは良いです。
  3. DDLは自動コミットします。これにより、ロックが解放されます。

テーブルがロックされている間、DMLステートメントは「待機」するか、開発者がそれを「ハング」します。

パーティションを削除するジョブから実行されるコードでこれを使用します。正常に動作します。これは、数百挿入/秒の速度で常に挿入されているデータベースにあります。エラーはありません。

あなたが疑問に思っているなら。11gでこれを行う。過去にもこれを10gでやったことがあります。


3
はい、これは間違っています。11gでは、set_ddl_timeoutを使用します。これは11gでのみ使用できます。oracleはDDLを実行する前にコミットを行うため、ロックを解放します。11gでは、DDLを待機させることができます。私は今それをやっています。正常に動作します。
ボブ

3
11gでは、LOCK TABLE table_name IN EXCLUSIVE MODEを使用する必要があります。
カミルローマ2015

1
これは、バッチジョブからORA-00054を取得している場合に非常に便利ですが、ここに着陸するほとんどの人々(OPと私を含む)が開発を行っており、同じテーブルで挿入を実行しているセッションを開いたままにしていると思います。ドロップして再作成しようとしています。KILL SESSIONこれらの人々にとって正しい答えです。
Andrew Spencer

@Bob 11gと古い方法の両方のサンプルコードはいいでしょう。構文はset_ddl_timeout何ですか?それは何ですか?
vapcguy

1
@vapcguyこれは11gで私にとってうまくいきました:ドキュメントをALTER SYSTEM SET ddl_lock_timeout=20;参照してください
rshdev

13

このエラーは、リソースがビジーのときに発生します。クエリに参照制約があるかどうかを確認します。または、クエリで言及したテーブルでさえビジーである可能性があります。彼らは、次のクエリ結果に間違いなくリストされる他の仕事に従事している可能性があります。

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

SIDを見つけます。

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

1
誰もがこれらのビューにアクセスできるわけではありません。わかりますORA-00942: table or view does not exist
vapcguy

そのような場合、DB管理者はそれらの情報を提供する責任があります。
Arunchunaivendan 2017年

常にではない。私はコードでこれを理解して回避する必要があり、私も私のサービスアカウントもこれらの権限を持ちません。
vapcguy 2017年

7

これは、テーブルの変更に使用されたセッション以外のセッションが、DML(更新/削除/挿入)が原因でロックを保持している場合に発生します。新しいシステムを開発している場合、あなたまたはあなたのチームの誰かが更新ステートメントを発行し、あまり影響なくセッションを終了する可能性があります。または、誰がセッションを開いているかがわかったら、そのセッションからコミットできます。

SQL管理システムにアクセスできる場合は、それを使用して問題のセッションを見つけます。そしておそらくそれを殺します。

v $ sessionやv $ lockなどを使用することもできますが、そのセッションを見つける方法と、それを強制終了する方法をググるように勧めます。

実動システムでは、それは本当に依存します。Oracle 10g以前の場合、次のコマンドを実行できます

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

別のセッションで、時間がかかりすぎる場合に備えて次の準備をします。

alter system kill session '....

それはあなたが持っているシステムに依存します、古いシステムは毎回コミットしない可能性が高くなります。ロックが長く続く可能性があるため、これは問題です。したがって、あなたのロックは新しいロックを防ぎ、いつ解放されるかを知っているロックを待ちます。これが、他のステートメントの準備ができている理由です。または、同様の処理を自動的に実行するPLSQLスクリプトを探すこともできます。

バージョン11gには、待機時間を設定する新しい環境変数があります。それはおそらく私が説明したものと同様の何かを行うと思います。ロックの問題は解消されないことに注意してください。

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

最後に、システム内にこの種のメンテナンスを行うユーザーが少なくなるまで待つのが最善です。


またalter system kill session '....、管理ビューへのアクセス権がない場合、どのようにして殺すセッションを見つけますか?
vapcguy

わからない。
Arturo Hernandez 2017年

7

私の場合は、自分のセッションの 1つがブロックしいることを確信していました。したがって、以下を実行しても安全でした。

  • 私は問題のあるセッションを見つけました:

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

    セッションは非アクティブでしたが、それでも何らかの理由でロックが保持されていました。場合によっては、他のWHERE条件を使用する必要があることに注意してください(たとえば、try USERNAMEまたはMACHINEfields)。

  • を使用してセッションを終了し、上記IDSERIAL#取得しました。

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

@thermzによる編集:以前のオープンセッションクエリがどれも機能しない場合は、これを試してください。このクエリは、セッションを強制終了するときに構文エラーを回避するのに役立ちます。

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

以前のオープンセッションクエリがどれも機能しない場合は、これを試してください。
thermz

5

セッションを保持しているプロセスを確認し、それを強制終了してください。正常に戻った。

以下のSQLはあなたのプロセスを見つけるでしょう

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;

その後、それを殺します

ALTER SYSTEM KILL SESSION 'sid,serial#'

または

オンラインで見つけたいくつかの例では、インスタンスIDを変更し、システムのkillセッション '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

テーブルを作成するだけでこのエラーが発生しました!まだ存在していないテーブルには明らかに競合の問題はありませんでした。CREATE TABLE声明は含まれてCONSTRAINT fk_name FOREIGN KEYよく人口テーブルを参照するWHERE句を。そうしなければならなかった:

  • CREATE TABLEステートメントからFOREIGN KEY句を削除する
  • FK列にINDEXを作成します
  • FKを作成する

私は同じ問題を抱えていました。dkステートメントからfk定義を削除した後でテーブルを作成できましたが、列にインデックスを作成した後でも追加できません。
vadipp '20

解決できました。まず、にnovalidate句を追加しましたalter table add constraint。これはどういうわけかそれを実行させますが、それはロックします。次に、セッションロックを調べて、ロックしているセッションを確認しました。その後、そのセッションを終了しました。
vadipp

3

2つのスクリプトを実行していたときに、このエラーが発生しました。私が持っていた:

  • スキーマユーザーアカウント(アカウント#1)を使用して直接接続されたSQL * Plusセッション
  • 別のSQL * Plusセッションは、異なるスキーマユーザーアカウント(アカウント#2)を使用して接続しましたが、データベースリンクを介して最初のアカウントとして接続しました

テーブルドロップを実行してから、アカウント#1としてテーブルを作成しました。アカウント#2のセッションでテーブルの更新を実行しました。変更をコミットしませんでした。アカウント#1としてテーブルのドロップ/作成スクリプトを再実行しました。でエラーが発生しましたdrop table xコマンドで。

COMMIT;アカウント#2のSQL * Plusセッションで実行することで解決しました。


テーブルを削除する権限がない場合は、どうしますか?悪い答え
シェイカーフセイン

1
シェイカー、それは私に起こったときに私がやっていたことのほんの一例であり、問​​題の解決策ではありません-それは私の最後の行にありました-を実行しましたCOMMIT;。テーブルをドロップすることさえできない場合、そもそもこの問題につながるような変更を行う権限がありません。
vapcguy

-2

私も同様の問題に直面しています。このエラーを解決するためにプログラマが行うべきことは何もありません。オラクルDBAチームに連絡しました。彼らはセッションを殺し、魅力のように働いた。


1
誰かはまだ何かをしなければなりません。DBAチームが何をすべきか、およびセッションを強制終了する方法がわからない場合はどうなりますか?悪い答え。
vapcguy

1
セッションを終了する方法がわからない場合、DBAは仕事に不向きです
Shakeer Hussain

誰もが誤ってしまうのを避けるために、時々構文の復習が必要です。
vapcguy

-5

シャシのリンクで与えられた解決策は最高です... dbaや誰かに連絡する必要はありません

バックアップを作成

create table xxxx_backup as select * from xxxx;

すべての行を削除

delete from xxxx;
commit;

バックアップを挿入します。

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

10
削除/切り捨ては互換性がありません。多数の削除を実行すると、パフォーマンスに大きな影響があります。これは本当に悪いです。
ボブは

これは一般的なパターンだと思いました。
Shawn Xue、2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.