转自
https://blogs.oracle.com/database4cn/vsession-%E4%BD%A0%E7%9C%8B%E5%88%B0%E7%9A%84event%E7%9C%9F%E7%9A%84%E6%98%AFsession%E5%BD%93%E5%89%8D%E7%9A%84%E7%AD%89%E5%BE%85%E4%BA%8B%E4%BB%B6%E4%B9%88-v2
当数据库出现性能问题的时候,几乎所有的DBA都会通过v$session来查询数据库的等待。但是,您可曾想过,您用于查询session等待的SQL是正确的么?您看到的event可能并不是session当前的等待,下面举例来说明:
如下的一段简单的PL/SQL Block代码是一个死循环,很显然,它会持续的ON CPU
begin
while true loop
null;
end loop;
end;
/
下面我们用以上代码做一个测试。
--开启一个sqlplus,先确定当前sesison的sid和spid
select s.sid,s.serial#,p.spid from v$session s, v$process p, (select * from v$mystat where rownum=1) ms where s.paddr=p.addr and s.sid=ms.sid;
SID SERIAL# SPID
---------- ---------- ------------------------
283 55044 30176
--然后在这个sqlplus中执行以上PL/SQL代码:
begin
while true loop
null;
end loop;
end;
/
--再开启一个新的session,观察以上session 283的等待:
set line 200 pages 1000
col username for a5
col event for a30
select sid,serial#,status,sql_id,event,seq# from v$session where sid=283;
SID SERIAL# STATUS SQL_ID EVENT SEQ#
---------- ---------- -------- ------------- ------------------------------ ----------
283 55044 ACTIVE 1dn7nmztb2jaz SQL*Net message from client 247
--验证一下sql文本
col sql_text for a60
select sql_id,sql_text from v$sql where sql_id='1dn7nmztb2jaz';
SQL_ID SQL_TEXT
------------- ------------------------------------------------------------
1dn7nmztb2jaz begin while true loop null; end loop; end;
您会发现以上这个session竟然会在 "等待" SQL*Net message from client,并且status为ACTIVE,大家都知道SQL*Net message from client是一个空闲等待,代表server process正在等待client发出下一个sql指令。
接下来观察以上以上进程的CPU消耗情况,会发现它在持续的ON CPU
# top -p 30176
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
30176 oracle 20 0 1470m 89m 80m R 47.0 1.1 2:38.91 oracle_30176_or
它几乎消耗了一半的CPU(本测试机为两个CPU),这符合代码的特点。
那么问题来了,这个如此烧CPU的死循环session怎么会是处于空闲等待?答案是我们忽略了v$session.state这个非常重要的列。
一个session的状态要么是在等待,要么是在ON CPU,v$session.state这个列可以判断这个状态。有且只有v$session.state='WAITING'的时候,才代表这个session当前正在等待这个event,否则代表这个session在ON CPU,并且观察到的event只是进程在ON CPU之前的最后一个等待。
接下来我们将以上用于查询session等待的SQL改一下,添加上v$session.state这个列:
col state fro a15
select sid,serial#,status,state,sql_id,event,seq# from v$session where sid=283;
SID SERIAL# STATUS STATE SQL_ID EVENT SEQ#
---------- ---------- -------- ------------------- ------------- ------------------------------ ----------
283 55044 ACTIVE WAITED KNOWN TIME 1dn7nmztb2jaz SQL*Net message from client 247
可见STATE的值为"WAITED KNOWN TIME",不是"WAITING",这表明这个session当前在ON CPU,"SQL*Net message from client"只是这个session在ON CPU之前的最后一个等待。因此当您查询v$session观察session的等待事件的时候,一定不要忘了v$session.state这个关键列。