5

Oracle 11gR2 で、「クライアントからの SQL*Net メッセージ」イベントでMERGEハングするブロックされた (しかしアイドル状態の!) ステートメントを含む非常に興味深い状況に最近遭遇しました。カーソル: ピン S は X"イベントで待機します。Oracle Enterprise Manager では、次のことが確認できます。MERGE

ここに画像の説明を入力

上記のセッション ID 1204 は次のいずれでも強制終了できないため、この状況はさらに深刻になります。

alter system kill session 'sid,serial#';
alter system kill session 'sid,serial#' immediate;

DBA はオペレーティング システムのプロセスを強制終了できる場合もありますが、多くの場合、データベース全体を再起動する必要があります。幸いなことに、これまでのところ、テスト システム上でのみ使用されており、運用環境では使用されていません。

ノート:

これはおそらく、このかなり漠然とした質問で報告されているのと同様の問題であることを認識しています: Oracle の更新/挿入がスタックし、DB CPU が 100% で、同時実行性が高く、クライアントからの SQL*Net 待機メッセージ。回答として報告する明確な再現パスがあるので、もう一度報告します。

4

1 に答える 1

9

これは、ステートメントの句CLOBに渡される値としてデータ型が使用されている場合の Oracle のバグのようです。次のデータベースを想定します。MERGEON

CREATE TABLE t (
  v INT, 
  s VARCHAR2(400 CHAR)
);

インライン値を使用した再現

ここで、SQL*Plus、SQL Developer、または JDBC を含む任意の Oracle クライアントで次のステートメントを実行すると、問題を非常に簡単に再現できます (私は Oracle 11g XE 11.2.0.2.0 を使用しています)。

MERGE INTO t                      
USING (
  SELECT 
    1 v, 
    CAST('abc' AS CLOB) s 
  FROM DUAL
) s 
ON (t.s = s.s) -- Using a CLOB here causes the bug.
WHEN MATCHED THEN UPDATE SET
  t.v = s.v        
WHEN NOT MATCHED THEN INSERT (v, s) 
VALUES (s.v, s.s);

例はばかげており、CLOBここでは「偶然」に拘束されていました。それにもかかわらず、そのようなステートメントは Oracle でゾンビ セッションを作成するべきではありませんが、存在します。SQL*Plus で上記のステートメントを 3 回実行してから、これを実行しています...

SELECT 
  s.sid,
  s.serial#,
  s.sql_id,
  s.event,
  s.blocking_session,
  q.sql_text
FROM v$session s
JOIN v$sql q
ON s.sql_id = q.sql_id
WHERE s.username = 'TEST'
AND UPPER(TRIM(q.sql_text)) LIKE 'MERGE%';

...私は得る:

sid serial# sql_id          event                       blocking_session
9   3       82a2k4sqzy1jq   cursor: pin S wait on X     92
49  89      82a2k4sqzy1jq   cursor: pin S wait on X     92
92  13      82a2k4sqzy1jq   db file sequential read     

報告されたイベント ( 「db file sequential read」 ) が、バインド変数を使用していた元のイベント ( 「SQL*Net message from client」 ) とどのように異なるかに注目してください。

バインド値を使用した再現

var v_s varchar2(50)
exec :v_s := 'abc'

MERGE INTO t                      
USING (
  SELECT 
    1 v, 
    CAST(:v_s AS CLOB) s 
  FROM DUAL
) s 
ON (t.s = s.s) -- Using a CLOB here causes the bug.
WHEN MATCHED THEN UPDATE SET
  t.v = s.v        
WHEN NOT MATCHED THEN INSERT (v, s) 
VALUES (s.v, s.s);

上記のステートメントを SQL*Plus で実行すると、次のバグも発生します。

sid serial# sql_id          event                           blocking_session
8   1       4w9zuxrumumgj   SQL*Net message from client     
90  7       4w9zuxrumumgj   cursor: pin S wait on X         8
94  21      4w9zuxrumumgj   cursor: pin S wait on X         8

PL/SQLでの再現なし

興味深いことに、このバグは次の PL/SQL ステートメントで回避されています。

DECLARE
  v_s CLOB := 'abc';
BEGIN
  MERGE INTO t                      
  USING (
    SELECT 
      1 v, 
      CAST(v_s AS CLOB) s 
    FROM DUAL
  ) s 
  ON (t.s = s.s) -- Using a CLOB here causes the bug.
  WHEN MATCHED THEN UPDATE SET
    t.v = s.v        
  WHEN NOT MATCHED THEN INSERT (v, s) 
  VALUES (s.v, s.s);
END;
/

私は得ています:

          CAST(v_s AS CLOB) s
          *
ERROR at line 8:
ORA-06550: line 8, column 11:
PL/SQL: ORA-00932: inconsistent datatypes: expected - got CLOB
ORA-06550: line 4, column 7:
PL/SQL: SQL Statement ignored

PL/SQL エンジンは、この SQL エンジンのバグからクライアントを保護しているように見えます。

于 2015-07-24T09:27:11.193 に答える