软解析、硬解析的一个小测试

看到这个帖子http://www.itpub.net/744933.html 的提问,做两个简单测试,由于近期较忙,文中解释内容比较少,希望抛砖引玉,
大家讨论。



SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%'
3 ;

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 32127
parse count (hard) 30365
parse count (failures) 1

SQL>
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'insert into test values('||i||','||i||')';
4 end loop;
5 commit;
6 end;
7 /

PL/SQL procedure successfully completed

SQL>
SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42201
parse count (hard) 40379
parse count (failures) 1

没有使用绑定变量(这种写法往往有人误认为使用了绑定,这里就不多解释了)
总解析次数:10074
硬解析次数:10014
上边2个值除了我们的循环10000次外,还包括其他一些系统表的读写,所以解析次数大于10000,但是我们要注意下面的结果,对于每个SQL
都有一个版本,也就是ORACLE对于每个不同的SQL分别执行了硬解析,下面是共享池最后缓存的数据(部分已经被覆盖)

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
insert into test values(9630,9630) 1 1 1
insert into test values(9950,9950) 1 1 1
insert into test values(9625,9625) 1 1 1
insert into test values(9592,9592) 1 1 1
insert into test values(9940,9940) 1 1 1
insert into test values(9897,9897) 1 1 1
insert into test values(9679,9679) 1 1 1
insert into test values(9850,9850) 1 1 1
insert into test values(9744,9744) 1 1 1
insert into test values(9938,9938) 1 1 1
insert into test values(9977,9977) 1 1 1
insert into test values(9907,9907) 1 1 1
insert into test values(9809,9809) 1 1 1
insert into test values(9800,9800) 1 1 1
insert into test values(9645,9645) 1 1 1
insert into test values(9724,9724) 1 1 1
insert into test values(9799,9799) 1 1 1
insert into test values(9818,9818) 1 1 1
insert into test values(9642,9642) 1 1 1
insert into test values(9624,9624) 1 1 1

中间内容略

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
insert into test values(9838,9838) 1 1 1
insert into test values(9716,9716) 1 1 1
insert into test values(9691,9691) 1 1 1
insert into test values(9831,9831) 1 1 1
insert into test values(9992,9992) 1 1 1
insert into test values(9883,9883) 1 1 1
insert into test values(9865,9865) 1 1 1
insert into test values(9901,9901) 1 1 1
insert into test values(9657,9657) 1 1 1
insert into test values(10000,10000) 1 1 1
insert into test values(9659,9659) 1 1 1
insert into test values(9746,9746) 1 1 1
insert into test values(9695,9695) 1 1 1
insert into test values(9869,9869) 1 1 1
insert into test values(9804,9804) 1 1 1
insert into test values(9843,9843) 1 1 1

435 rows selected

SQL> truncate talbe sess_event;

truncate talbe sess_event

ORA-03290: 无效的截断命令 - 缺失 CLUSTER 或 TABLE 关键字

SQL> truncate table sess_event;

Table truncated

SQL> alter system flush shared_pool;

System altered

SQL>
SQL> insert into sess_event
2 select * from v$session_event
3 where sid=(select sid from v$mystat where rownum=1);

10 rows inserted

SQL>
SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42643
parse count (hard) 40456
parse count (failures) 2

SQL>
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'insert into test values(:v1,:v2)' using i,i;
4 end loop;
5 commit;
6 end;
7 /

PL/SQL procedure successfully completed

SQL>
SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42688
parse count (hard) 40466
parse count (failures) 2

下面看下使用绑定变量的情况(真正使用了绑定)
总解析次数:45
硬解析次数:10
我们可以看出差异是多么大了,呵呵,对于SQL本身只有一次软解析,执行次数为10000

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
begin for i in 1..10000 loop execute immediate 'insert into test values(:v1,:v2 1 1 1
update sys.job$ set failures=0, this_date=null, flag=:1, last_date=:2, next_dat 1 1 1
insert into test values(:v1,:v2) 1 1 10000
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1

SQL> alter system flush shared_pool;

System altered

但是我们要注意一个情况,即时同样的SQL如果没有使用绑定变量,ORACLE也会对其执行一次软解析的,但是没有硬解析,如下:
每执行一次SQL,也会同时产生其他写系统表等很多相关的软解析包括查询SQL本身。硬解析不变。
SQL> insert into test values('1','1111111111');

1 row inserted

SQL> commit;

Commit complete

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
update sys.job$ set failures=0, this_date=null, flag=:1, last_date=:2, next_dat 1 1 1
insert into test values('1','1111111111') 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1

SQL> insert into test values('1','1111111111');

1 row inserted

SQL> commit;

Commit complete

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
update sys.job$ set failures=0, this_date=null, flag=:1, last_date=:2, next_dat 1 1 1
insert into test values('1','1111111111') 1 2 2
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 2 2

SQL>

SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42906
parse count (hard) 40520
parse count (failures) 2

SQL> insert into test values('1','1111111111');

1 row inserted

SQL> commit;

Commit complete

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
begin dbsnmp.mgmt_response.get_latest_curs(:a); end; 1 1 1
/* OracleOEM */ BEGIN IF (:1 = 'READ WRITE') THEN ---- -- For a read- 1 1 1
/* OracleOEM */ DECLARE instance_number NUMBER; latest_task_id NUMBER; 1 1 1
update sys.job$ set failures=0, this_date=null, flag=:1, last_date=:2, next_dat 1 4 4
insert into test values('1','1111111111') 1 3 3
DELETE FROM MGMT_DB_LATEST_HDM_FINDINGS WHERE TARGET_GUID = :B2 AND COLLECTION_T 2 3 3
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 3 3

8 rows selected

SQL>
SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42922
parse count (hard) 40520
parse count (failures) 2

SQL> insert into test values('1','1111111111');

1 row inserted

SQL> commit;

Commit complete

SQL> insert into test values('1','1111111111');

1 row inserted

SQL> commit;

Commit complete

SQL> select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper(sql_text) like '%TEST%';

SQL_TEXT VERSION_COUNT PARSE_CALLS EXECUTIONS
-------------------------------------------------------------------------------- ------------- ----------- ----------
begin dbsnmp.mgmt_response.get_latest_curs(:a); end; 1 1 1
/* OracleOEM */ BEGIN IF (:1 = 'READ WRITE') THEN ---- -- For a read- 1 1 1
/* OracleOEM */ DECLARE instance_number NUMBER; latest_task_id NUMBER; 1 1 1
update sys.job$ set failures=0, this_date=null, flag=:1, last_date=:2, next_dat 1 5 5
insert into test values('1','1111111111') 1 5 5
DELETE FROM MGMT_DB_LATEST_HDM_FINDINGS WHERE TARGET_GUID = :B2 AND COLLECTION_T 2 3 3
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 1 1
select SQL_TEXT,VERSION_COUNT,PARSE_CALLS,EXECUTIONS from v$sqlarea where upper( 1 4 4

8 rows selected

SQL>
SQL> SELECT NAME,VALUE FROM V$MYSTAT A,V$STATNAME B WHERE A.STATISTIC#=B.STATISTIC#
2 AND NAME LIKE 'parse count%';

NAME VALUE
---------------------------------------------------------------- ----------
parse count (total) 42946
parse count (hard) 40520
parse count (failures) 2

SQL>


通过这个例子我们也就知道V$SQLAREA中的解析包含什么内容了。

/*******************METHOD OF GET SESSION INFO***********************/

以上例子我们直接从V$MYSTAT 获得的SESSION相关信息,类似测试中我们也可以利用一下方法来获得SESSION相关的信息。


SQL> CREATE GLOBAL TEMPORARY TABLE SESS_EVENT ON COMMIT PRESERVE ROWS AS SELECT * FROM V$SESSION_EVENT WHERE 1=0;

TABLE CREATED

SQL> INSERT INTO SESS_EVENT
SELECT * FROM V$SESSION_EVENT
WHERE SID=(SELECT SID FROM V$MYSTAT WHERE ROWNUM=1);

SQL> SELECT A.EVENT,(A.TOTAL_WAITS - NVL(B.TOTAL_WAITS,0)) TOTAL_WAITS,
(A.TIME_WAITED-NVL(B.TIME_WAITED,0)) TIME_WAITED
FROM
(SELECT * FROM V$SESSION_EVENT WHERE SID=(SELECT SID FROM V$MYSTAT WHERE ROWNUM=1)) A,
SESS_EVENT B
WHERE A.EVENT=B.EVENT(+)
AND (A.TOTAL_WAITS-NVL(B.TOTAL_WAITS,0))>0;

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/16875294/viewspace-526857/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/16875294/viewspace-526857/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值