テーブルを更新すると、なぜこのデータベースエラーが発生するのですか?
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' NO WAIT
したがって、別のセッションに開いているトランザクションがある場合、エラーが発生します。修正は...ドラムロールをお願いします。DDLの前に独自のロックを発行し、「NOWAIT」を省略します。
特記事項:
パーティションの分割/削除を行っている場合、Oracleはパーティションをロックするだけです。--つまり、パーティションのサブパーティションをロックするだけです。
だから...次の手順で問題を解決します。
DMLステートメントは、テーブルがロックされている間、「待機」するか、開発者が「ハング」と呼ぶようになります。
これを、ジョブから実行してパーティションを削除するコードで使用します。正常に動作します。これは、毎秒数百回の速度で絶えず挿入されているデータベースにあります。エラーはありません。
あなたが疑問に思っているなら。11gでこれを行います。私は過去にもこれを10gで行いました。
このエラーは、リソースがビジーのときに発生します。クエリに参照制約があるかどうかを確認します。または、クエリで言及したテーブルでさえビジーである可能性があります。彼らは、次のクエリ結果に確実にリストされる他の仕事に従事している可能性があります。
SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'
SIDを見つけて
SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id
私の場合、ブロックされていたのは自分のセッションの1つであると確信していました。したがって、次のことを行っても安全でした。
私は次のような問題のあるセッションを見つけました:
SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';
セッションは非アクティブでしたが、それでも何らかの形でロックを保持していました。場合によっては、他のWHERE条件(tryUSERNAME
やMACHINE
fieldsなど)を使用する必要がある場合があることに注意してください。
上記を使用してセッションを強制終了し、上記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(更新/削除/挿入)が原因でロックを保持している場合に発生します。新しいシステムを開発している場合は、あなたまたはあなたのチームの誰かが更新ステートメントを発行し、あまり影響を与えずにセッションを強制終了する可能性があります。または、誰がセッションを開いているかがわかったら、そのセッションからコミットすることもできます。
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);
最後に、この種のメンテナンスを行うユーザーがシステムに少なくなるまで待つのが最善かもしれません。
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#';
セッションを保持しているプロセスを確認して、それを強制終了します。通常に戻ります。
以下の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が必要であり、システムの強制終了セッション '130,620、@1'も変更されているようです。
他の回答で述べたように、このエラーは他のセッションで実行されている同時DML操作が原因で発生します。これにより、OracleはデフォルトのNOWAITオプションを使用してDDLのテーブルをロックできなくなります。
データベースに管理者権限がない場合、または他のセッションを強制終了/中断できない場合は、DDL操作の前に次のコマンドを使用することもできます。
alter session set DDL_LOCK_TIMEOUT = 30;
--Run your DDL command, e.g.: alter table, etc.
バックグラウンドジョブが大規模な挿入/更新操作を実行しているデータベースでこのエラーを繰り返し受け取り、セッションでこのパラメーターを変更すると、ロックを数秒待った後もDDLを続行できました。
詳細については、この回答に関するrshdevのコメント、oracle - baseのこのエントリ、またはDDL_LOCK_TIMEOUTの公式ドキュメントを参照してください。
問題は、DML操作とDDL操作が混在しているように見えます。この問題を説明する次のURLを参照してください。
実行しているスクリプトが2つあるときに、このエラーが発生しました。私が持っていた:
テーブルドロップを実行してから、アカウント#1としてテーブルを作成しました。アカウント#2のセッションでテーブルの更新を実行しました。変更をコミットしませんでした。アカウント#1としてテーブルドロップ/作成スクリプトを再実行しました。drop table x
コマンドでエラーが発生しました。
COMMIT;
アカウント#2のSQL*Plusセッションで実行することで解決しました。
テーブルを作成するだけで、なんとかこのエラーが発生しました。まだ存在していないテーブルでは、明らかに競合の問題はありませんでした。このCREATE TABLE
ステートメントには、CONSTRAINT fk_name FOREIGN KEY
人口の多いテーブルを参照する句が含まれていました。そうしなければならなかった:
私も同様の問題に直面しています。このエラーを解決するためにプログラマーがする必要はありません。OracleDBAチームに通知しました。彼らはセッションを殺し、魅力のように働きました。
Shashiのリンクによって提供される解決策が最善です...dbaまたは他の誰かに連絡する必要はありません
バックアップを作成する
create table xxxx_backup as select * from xxxx;
すべての行を削除します
delete from xxxx;
commit;
バックアップを挿入します。
insert into xxxx (select * from xxxx_backup);
commit;