5

在 Oracle 11gR2 上,我最近遇到了一个非常有趣的情况,涉及一个阻塞(但空闲!)MERGE语句挂在“来自客户端的 SQL*Net 消息”事件上,导致后续并发执行MERGE的语句通过“光标:引脚 S 等待 X"事件。在 Oracle Enterprise Manager 中,可以观察到以下情况:

在此处输入图像描述

这种情况变得更加严重,因为上面的 Session-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当数据类型被用作传递给MERGE语句ON子句的值时,这似乎是 Oracle 中的一个错误。假设这个数据库:

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

使用内联值进行复制

现在,在任何 Oracle 客户端(包括 SQL*Plus、SQL Developer 或 JDBC)中运行以下语句,这有助于非常轻松地重现问题(我使用的是 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 文件顺序读取” )与使用绑定变量的原始事件(“来自客户端的 SQL*Net 消息” )有何不同

使用绑定值进行复制

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 回答