为什么V$SESSSION下的SQL_ID有时候为NULL

SQL_ID和PREV_SQL_ID在我们日常监控会话的SQL语句中非常重要,有时候我们经常看到SQL_ID是空的情况,那么我们就会去找 PREV_SQL_ID的值来获取最后一次执行的SQL语句.那么有一个疑问?什么时候SQL_ID有值,什么时候它又是空的呢?下面我们会来做一个小实验,我的实验环境是Oracle 11gR2.通过实验来说明这个问题.

1.首先我们来模拟单会话查询;

>>>>>>>>session1>>>>>>>>
SQL> select sid from v$mystat where rownum=1;
SID
----------
403

select * from v$datafile where rownum=1;
select * from dba_tables where rownum=1;
select * from t1 where rownum=1; -------普通表
select * from aaa;               -------普通视图
select * from dba_tables;        ------------长查询

>>>>>>>>session2>>>>>>>>>
SQL> select sid,sql_id,PREV_SQL_ID from v$session where sid=403;
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 80hfhzra2uv3z
SQL> /

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 18s1d1fq9nzp2 18s1d1fq9nzp2
SQL> /

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 b61hdn491z56k
SQL> /

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 4njm39vk9m633

SQL> /
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 7tz9tdx2npk9t 4njm39vk9m633

在这里我们可以很清晰的看到,在我们运行长时间的sql查询时,我们正在运行的SQL_ID会是当前正在运行的sql语句.不过有个例外,在执行dba_tables这样的视图时,执行完之后,我们的 SQL_ID和PREV_SQL_ID都是有值的,而且保持一致.

2.接下来是DML测试.

>>>>>>>>session1>>>>>>>>
update test set id=5 where id=3;
commit;
update t4 set OWNER='ttt'; ---------t4 75273行
commit

>>>>>>>>session2>>>>>>>>>
SQL> select sid,sql_id,PREV_SQL_ID from v$session where sid=403;
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 38yz7yvht2268

SQL> /
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 38yz7yvht2268

SQL> /

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 60hhc0y04465g 60hhc0y04465g
SQL> /

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 60hhc0y04465g

只要一运行就会有PREV_SQL_ID,不管是提交还是回滚.如果是大批量并且不提交的情况下,SQL_ID和PREV_SQL_ID保持一致,提交或者回滚之后SQL_ID变为空.
下面是模拟锁定的情况.

>>>>>>>>session1>>>>>>>>
SQL> update test set id=5 where id=3;
1 row updated.
>>>>>>>>session2>>>>>>>>
SQL> select sid from v$mystat where rownum=1;
SID
----------
407
SQL> update test set id=5 where id=3;
>>>>>>>>session3>>>>>>>>
SQL> select sid,sql_id,PREV_SQL_ID from v$session where sid in (403,407);
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 38yz7yvht2268
407 38yz7yvht2268 dyk4dprp70d74

在DML语句出现锁定情况时,我们的阻塞者只会有PREV_SQL_ID,而被阻塞者会有SQL_ID.提交或者回滚之后,两者都只会有PREV_SQL_ID.

>>>>>>>>session1>>>>>>>>
SQL> commit;
Commit complete.
>>>>>>>>session3>>>>>>>>
SQL> select sid,sql_id,PREV_SQL_ID from v$session where sid in (403,407);

SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 38yz7yvht2268
407 38yz7yvht2268

3.DDL语句的测试

>>>>>>>>session1>>>>>>>>
SQL> create table t3
2 ( id number);
Table created.
SQL> alter table t3 add name varchar2(20);
Table altered.
SQL> truncate table t3;
Table truncated.
SQL> drop table t3;
Table dropped.
>>>>>>>>session3>>>>>>>>
SQL> select sid,sql_id,PREV_SQL_ID from v$session where sid =403;
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 0xmrqqc98s98c 0xmrqqc98s98c
SQL> /
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 g1d3zhz7wq0d4 g1d3zhz7wq0d4
SQL> /
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 b3pbmwjuzmw24 b3pbmwjuzmw24
SQL> /
SID SQL_ID PREV_SQL_ID
---------- ------------- -------------
403 7ajbnzrag3jrw

可以看到在运行create,alter,truncate的时候,SQL_ID和PREV_SQL_ID都是保持一致的,然而在运行drop语句的时候,SQL_ID是空的.

其实还有很多种情况,大家可以自己去模拟.我这里只是做个总结:
1.在基本普通查询中,查询完之后,SQL_ID和PREV_SQL_ID都有值,并且保持一致.
2.较长时间的查询,在查询过程中,SQL_ID存在,查完后SQL_ID将不复存在,取而代之的是PREV_SQL_ID.
3.短小DML语句,执行完后,只会有PREV_SQL_ID,不管你是提交还是回滚,都会存在.
4.长DML语句,执行完后,SQL_ID和PREV_SQL_ID都有值,并且保持一致.提交和回滚后,只有PREV_SQL_ID.
5.产生锁的时候, 阻塞者只会有PREV_SQL_ID,而被阻塞者会有SQL_ID和PREV_SQL_ID
6.DDL语句,create,alter,truncate,会有SQL_ID和PREV_SQL_ID,drop只会有PREV_SQL_ID.

分享到: 更多

Post a Comment

Your email is never published nor shared. Required fields are marked *