无法终止的 Oracle 会话正在等待 "SQL*Net message from client" 事件
Unkillable Oracle session waiting on "SQL*Net message from client" event
在 Oracle 11gR2 上,我最近遇到了一个非常有趣的情况,涉及阻塞(但空闲!)MERGE
语句挂在 "SQL*Net message from client" 事件,导致后续并发执行的 MERGE
语句通过 "cursor: pin S wait on X" 事件阻塞在第一条语句上。在 Oracle Enterprise Manager 中,可以观察到以下内容:
这种情况变得更加严重,因为上面的 Session-ID 1204 不能被杀死:
alter system kill session 'sid,serial#';
alter system kill session 'sid,serial#' immediate;
我们的 DBA 有时可以杀死操作系统进程,但通常需要重新启动整个数据库。幸运的是,到目前为止,只在测试系统上,从未在生产中。
注:
我知道这可能与这个相当模糊的问题中报告的问题类似:Oracle updates/inserts stuck, DB CPU at 100%, concurrency high, SQL*Net wait message from client。我还是会重新报告,因为我有明确的复制路径,我会报告为答案。
当 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
在这里被"accident"绑定了。尽管如此,这样的语句不应该在 Oracle 中创建僵尸会话,但它确实存在。我在 SQL*Plus 中 运行 将上述语句执行了三次,然后 运行 执行了这个...
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 引擎错误的影响。
在 Oracle 11gR2 上,我最近遇到了一个非常有趣的情况,涉及阻塞(但空闲!)MERGE
语句挂在 "SQL*Net message from client" 事件,导致后续并发执行的 MERGE
语句通过 "cursor: pin S wait on X" 事件阻塞在第一条语句上。在 Oracle Enterprise Manager 中,可以观察到以下内容:
这种情况变得更加严重,因为上面的 Session-ID 1204 不能被杀死:
alter system kill session 'sid,serial#';
alter system kill session 'sid,serial#' immediate;
我们的 DBA 有时可以杀死操作系统进程,但通常需要重新启动整个数据库。幸运的是,到目前为止,只在测试系统上,从未在生产中。
注:
我知道这可能与这个相当模糊的问题中报告的问题类似:Oracle updates/inserts stuck, DB CPU at 100%, concurrency high, SQL*Net wait message from client。我还是会重新报告,因为我有明确的复制路径,我会报告为答案。
当 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
在这里被"accident"绑定了。尽管如此,这样的语句不应该在 Oracle 中创建僵尸会话,但它确实存在。我在 SQL*Plus 中 运行 将上述语句执行了三次,然后 运行 执行了这个...
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 引擎错误的影响。