テーブルを更新すると、なぜこのデータベースエラーが発生するのですか?
1行目のエラー:ORA-00054:リソースがビジーで、NOWAITを指定して取得したか、タイムアウトになりました
あなたのテーブルはすでに何らかのクエリによってロックされています。たとえば、「select for update」を実行し、まだコミット/ロールバックしていないため、別のselectクエリを実行したとします。クエリを実行する前にコミット/ロールバックを行います。
ここから ORA-00054:リソースがビジーで、NOWAITを指定して取得しています
また、SQL、ユーザー名、マシン、ポート情報を調べて、接続を保持している実際のプロセスにアクセスすることもできます。
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;
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
この問題には非常に簡単な回避策があります。
あなたがあなたのセッションで10046トレースを実行するならば(これをグーグル...説明するには多すぎる)。 DDL操作の前に、Oracleによって次の処理が行われることがわかります。
LOCK TABLE 'TABLE_NAME'はお待ちください
そのため、他のセッションが開いているトランザクションを持っているとエラーになります。だから修正は...ドラムロールしてください。 DDLの前にあなた自身のロックを発行し、 'NO WAIT'を除外してください。
特記事項
パーティションの分割/削除を実行している場合、Oracleはパーティションをロックするだけです。 - パーティションのサブパーティションをロックするだけです。
だから...次の手順は問題を解決します。
DML文は、テーブルがロックされている間は「待機」または開発者が「ハング」と呼びます。
私はこれをジョブから実行するコードで使用してパーティションを削除します。それはうまくいきます。データベースには、毎秒数百挿入の割合で挿入されています。エラーなし.
あなたが疑問に思っているならば。 11gでこれをやる。私は過去にも同様に10gでこれをしました。
このエラーは、リソースが使用中のときに発生します。照会に参照制約があるかどうかを確認してください。あるいは、あなたがクエリで言及したテーブルさえビジーかもしれません。彼らは他の仕事に携わっているかもしれませんが、それらは以下の問い合わせ結果に間違いなく記載されています。
SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'
SIDを見つけます。
SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
これは、表の変更に使用されたセッション以外のセッションがDML(更新/削除/挿入)のためにロックを保持しているときに発生します。もしあなたが新しいシステムを開発しているのであれば、あなたまたはあなたのチームの誰かがupdateステートメントを発行し、あなたが大きな影響なしにセッションを終了させる可能性があります。あるいは、誰がセッションを開いているのかがわかったら、そのセッションからコミットすることもできます。
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);
最後に、この種のメンテナンスを行うユーザーがシステムにほとんどいなくなるまで待つのが最善の方法です。
私の場合、それが 私自身のセッション のうちの1つであることを確信していました - /それはブロックしていました。したがって、次のことを行っても安全でした。
次のような問題のあるセッションが見つかりました。
SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';
セッションは 非アクティブ でしたが、それでも何らかの理由でロックを保持していました。あなたのケースでは他の _ where _ 条件を使う必要があるかもしれないことに注意してください(例えばUSERNAME
やMACHINE
フィールドを試してください)。
上記で取得したID
とSERIAL#
を使用してセッションを終了しました。
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'
DMLとDDLの操作が混在しているように見えます。この問題を説明している次のURLを参照してください。
セッションを保持しているプロセスを確認して終了してください。通常の状態に戻ります。
以下の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#'
OR
私がオンラインで見つけたいくつかの例はインスタンスIDを必要とし、システムの強制終了セッションを変更するようです '130,620、@ 1'。
単純にテーブルを作成するとき、私はなんとかこのエラーにぶつかった!まだ存在していないテーブルには、明らかに競合の問題はありませんでした。 CREATE TABLE
ステートメントには、データの入っている表を参照するCONSTRAINT fk_name FOREIGN KEY
文節が含まれていました。そうしなければならなかった:
実行していた2つのスクリプトがあると、このエラーが発生しました。私は持っていました:
テーブルをドロップしてから、アカウント#1としてテーブルを作成しました。アカウント#2のセッションでテーブルを更新しました。変更をコミットしませんでした。テーブル#ドロップ/作成スクリプトをアカウント#1として再実行しました。 drop table x
コマンドでエラーが発生しました。
アカウント#2のSQL * PlusセッションでCOMMIT;
を実行することで解決しました。