1.用示例说明绑定变量的应用领域是OLTP而不是OLAP。<br>
2.用示例演示一次硬分析(hard parse)和一次软分析(soft parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>
3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>
5.演示ACS(adaptiver cursor sharing)的效果。<br>
==================================================================================
1.用示例说明绑定变量的应用领域是OLTP而不是OLAP。<br>
答:
1.1 示例说明
SQL> drop table t1 purge;
Table dropped.
SQL> create table t1 as select * from dba_objects;
Table created.
SQL> alter session set tracefile_identifier='bind_var';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> begin
2 for i in 1..100 loop
3 execute immediate 'select * from t1 where object_id=:i' using i;
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> alter session set sql_trace=false;
Session altered.
SQL> select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %';
select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %'
*
ERROR at line 1:
ORA-00904: "PASE_CALLS": invalid identifier
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from t1%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
----------- ---------- ---- ----------
select * from t1 where object_id=:i 1 1 100
从上面的查询中,可以看到,在重复执行了100次的查询中,有1次的硬解析,
1.2 下面再进行一个非绑定变量的SQL 执行情况:
SQL> alter session set sql_trace=true; 启动trace功能
Session altered.
SQL> begin
for i in 1..100 loop
execute immediate 'select * from T where object_id='||i;
end loop;
end;
/
PL/SQL procedure successfully completed.
我们对一条sql执行了100次没有采用绑定变量技术,oracle对这条sql要硬解析100次,执行100次,CPU的消耗就有了100次。
SQL> alter session set sql_trace=false; 关闭trace功能
Session altered.
LEO1@LEO1> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from T1 where %' order by 1;
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
---------------------- ---------- ---------- ----------
select * from t1 where object_id=1 1 1 1
....
select * from t1 where object_id=100 1 1 1
100 rows selected.
SQL>
再来查看一下跟踪文件:
1.3 使用绑定变量跟踪部分:
D:\app\oracle\diag\rdbms\orcl\orcl\trace>tkprof orcl_ora_5528_bind_var.trc out_b
ind.log
TKPROF: Release 11.2.0.3.0 - Development on 星期四 12月 5 17:58:35 2013
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
SQL ID: 28gj7tsy13xq8 Plan Hash: 3617692013
select *
from
t1 where object_id=:i
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.01 0.00 0 1 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.01 0.00 0 1 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=3 us cost=305 size=2484 card=12)
********************************************************************************
1.4 没使用绑定变量跟踪部分:
begin
for i in 1..100 loop
execute immediate 'select * from t1 where object_id='||i;
end loop;
end;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.01 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.02 0 0 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
SQL ID: 9vx4vjbr7qrnn Plan Hash: 2586623307
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE
NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false')
NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"),
NVL(SUM(C2),:"SYS_B_1")
FROM
(SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T1") FULL("T1")
NO_PARALLEL_INDEX("T1") */ :"SYS_B_2" AS C1, CASE WHEN "T1"."OBJECT_ID"=
:"SYS_B_3" THEN :"SYS_B_4" ELSE :"SYS_B_5" END AS C2 FROM "TANG"."T1"
SAMPLE BLOCK (:"SYS_B_6" , :"SYS_B_7") SEED (:"SYS_B_8") "T1") SAMPLESUB
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 100 0.00 0.01 0 0 0 0
Execute 100 0.00 0.00 0 0 0 0
Fetch 100 0.18 0.16 0 6900 0 100
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 300 0.18 0.17 0 6900 0 100
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 2)
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=69 pr=0 pw=0 time=1701 us)
4452 4452 4452 TABLE ACCESS SAMPLE T1 (cr=69 pr=0 pw=0 time=4608 us cost=19 size=128650 card=5146)
********************************************************************************
SQL ID: d44dqxf5hgz0j Plan Hash: 3617692013
select *
from
t1 where object_id=1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 1 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=2 us cost=305 size=2484 card=12)
********************************************************************************
从上面使用了绑定变量的方法,可以看到,执行100次,只有一次硬解析。
而非绑定变量方法,每一次的SQL,都是独立解析及运行的。CPU的消耗也可以看到两者的差异。
1.4.绑定变量的SQL代码优化,主要是减少了SQL 的硬解析。
1.5 在OLTP 架构中,
1.5.1 SQL 简单而非常相似,并且结果集非常小,不同的只是谓语部分。所以这种情况下,执行计划都是一样的。
在执行计划都几乎不变的情况下。ORACLE使用变量来代替谓词,使用同一个执行计划,是非常合理的。
1.5.2 SQL 重复率很高,或者只是谓词条件不同而已;
1.5.3 SQL 语句执行条件多,条数越多,CPU的消耗就大,这种情况下,减少硬解析就越有意义了。
1.6 在OLAP 架构中
1.6.1 SQL 执行的重复率低,大部分都只是批量,定时加载,
1.6.2 数据聚合操作频繁;
1.6.3 SQL 语句执行条数少,SQL 硬解析对系统性能影响较小,更多的瓶颈是IO,
1.6.3 分区表的查询,相对也不太适合绑定变量技术.
综上所述,所以说OLAP不适合使用绑定变量。
---------------------------------------------------------------------------------------------
2.用示例演示一次硬分析(hard parse)和一次软分析(soft parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>
ORACLE SQL 执行过程:
数据库端收到一个sql 请求后,会建立一个进程,与用户进程组成一个会话,在pga区处理sql 请求。
然后开始访问sga的sharl pool,并解析SQL,生成执行计划;
如果一条SQL 在share pool中已经存在,那么ORACLE 只需奖已存在的执行计划应用到当前SQL上,去访问数据即可。这种情况称之为软解析(SOFT PARSE);
如果在共享汇中没有找到SQL的执行计划,ORACLE就会对SQL 进行: 语法解析,语义解析,生成执行计划等动作,这些解析步骤就总称为硬解析(HARD PARSE);
而这些解析步骤是比较消耗资源的。
还有另外一种解析是:缓存游标信息,后续的SQL不用再去打开一个新的cursor,而是直接去share pool 中找到已查询过的数据,这样就更省资源,
成为更软的解析(SOFTER SOFT PARSE).
2.1 演示数据准备及第一次执行效果
SQL> drop table t2 purge;
Table dropped.
SQL> create table t2 as select * from dba_objects;
Table created.
SQL> select count(0) from t2;
COUNT(0)
----------
76429
查询SQL 运行情况
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 1 1 1
可以看到总解析 1次;硬解析 1次,执行次数 1 次;
下面我们再执行一次:
2.2 第二次执行效果
SQL> select count(0) from t2;
COUNT(0)
----------
76429
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 2 1 2
这时可以看到总解析 2次;硬解析 1次,执行次数 2 次; 第2次没有进行硬解析,就是因为SQL 放在
SHARED_POOL中,进行了一次软解析;
2.3 我们再把SHARED_POOL清空,看看效果:
SQL> alter system flush shared_pool;
System altered.
SQL> select count(0) from t2;
COUNT(0)
----------
76429
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 1 1 1
这时,ORACLE 认为是一条新的SQL了。所以又有一次硬解析。
2.4 softer_soft_parse 会话对游标的缓存
SQL> alter session set tracefile_identifier='tang';
Session altered.
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set events '10046 trace name context forever,level 12';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL>
SQL> show parameter session_cached_cursors;
NAME TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
session_cached_cursors integer
50
SQL> set linesize 100;
SQL> select 'STAT-'||name,value from v$sysstat where name like '%parse%' or name like'%cursor%'
2 union all select 'LATCH-'||name,gets from v$latch where name = 'shared pool';
'STAT-'||NAME VALUE
---------- ------------------------------
STAT-opened cursors cumulative 10897
STAT-opened cursors current 28
STAT-pinned cursors current 12
STAT-session cursor cache hits 12908
STAT-session cursor cache count 882
STAT-cursor authentications 237
STAT-parse time cpu 91
STAT-parse time elapsed 224
STAT-parse count (total) 1752
STAT-parse count (hard) 1271
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 98158
13 rows selected.
SQL>
SQL> select count(0) from t10;
COUNT(0)
----------
76432
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'select count(0) from t10';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' un
ets from v$latch where name = 'shared pool';
NAME VALUE
----------------------------------------
STAT-opened cursors cumulative 21492
STAT-opened cursors current 29
STAT-pinned cursors current 11
STAT-session cursor cache hits 23418
STAT-session cursor cache count 1033
STAT-cursor authentications 262
STAT-parse time cpu 96
STAT-parse time elapsed 230
STAT-parse count (total) 1887
STAT-parse count (hard) 1290
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 118288
13 rows selected.
SQL>
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set session_cached_cursors=0;
Session altered.
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
ets from v$latch where name = 'shared pool';
NAME VALUE
-------------------------------------------
STAT-opened cursors cumulative 26250
STAT-opened cursors current 28
STAT-pinned cursors current 11
STAT-session cursor cache hits 28300
STAT-session cursor cache count 1671
STAT-cursor authentications 363
STAT-parse time cpu 148
STAT-parse time elapsed 300
STAT-parse count (total) 2855
STAT-parse count (hard) 1620
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 153871
13 rows selected.
SQL> select count(0) from t10;
COUNT(0)
----------
76432
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'select count(0) from t10';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
ets from v$latch where name = 'shared pool';
NAME VALUE
----------------------------------------
STAT-opened cursors cumulative 39364
STAT-opened cursors current 30
STAT-pinned cursors current 10
STAT-session cursor cache hits 34321
STAT-session cursor cache count 1912
STAT-cursor authentications 442
STAT-parse time cpu 184
STAT-parse time elapsed 337
STAT-parse count (total) 13302
STAT-parse count (hard) 1814
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 177749
13 rows selected.
SQL>
---------------------------------------------------------------------------------------------
3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
3.1 使用不绑定变量,执行3次不同的SQL,是各自进行硬分析的:
SQL> alter system flush shared_pool;
System altered.
SQL> select object_id from t10 where object_id=100;
OBJECT_ID
----------
100
SQL> select object_id from t10 where object_id=200;
OBJECT_ID
----------
200
SQL> select object_id from t10 where object_id=300;
OBJECT_ID
----------
300
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%'
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
----------- ---------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=100 1 1 1
SQL>
3.2 使用绑定变量
SQL> var vid number;
SQL> execute :vid:=100;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id:=vid;
select object_id from t10 where object_id:=vid
*
ERROR at line 1:
ORA-00920: invalid relational operator
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
100
SQL> execute :vid:=150;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
150
SQL> execute :vid:=160;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
160
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
---------------------- ----------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=:vid 3 1 3
select object_id from t10 where object_id=100 1 1 1
SQL>
从上面最后的查询看到,最后一次使用变量的方式执行的3次SQL,只进行了一次硬分析
Oracle认为这3条SQL是完全一样的(除了谓词部分)所以第一次执行的时候做一次硬解析后续2条SQL只做软解析,比上一个少了2次硬解析,性能提高
绑定变量2
SQL> begin
2 for i in 1..3 loop
3 execute immediate 'select object_id from t10 where object_id=:i' using i;
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
-------------------------------------------- ----------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=:i 1 1 3
select object_id from t10 where object_id=:vid 3 1 3
select object_id from t10 where object_id=100 1 1 1
SQL>
Oracle认为这3条SQL是完全一样的(除了谓词部分),和上面不同的是只做了1次硬解析没有软解析,反复执行了3次。
我们做了一个循环,用leo变量代替谓词常量,每次都用相同的执行计划(执行计划不需要重新生成),只是改变一下常量值而已。
上面3种执行方法,从上面的查询中,很好的看出各自的不同,优点最明显的就是最后一次的SQL.
---------------------------------------------------------------------------------------------
4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>
4.1 把用户TANG.10 的查询权限赋给 test,scott;
SQL> grant select on t10 to test;
Grant succeeded
SQL> grant select on t10 to scott;
Grant succeeded
SQL>
4.2 在test,scott 用户下各建立T10表;
C:\Users\Administrator>sqlplus test/test@orcl
SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:27:31 2013
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table t10 as select * from tang.t10;
Table created.
SQL> select count(1) from t10;
COUNT(1)
----------
76430
SQL>
C:\Users\Administrator>sqlplus scott/scott@orcl
SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:30:24 2013
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table t10 as select * from tang.t10;
Table created.
SQL> select count(1) from t10;
COUNT(1)
----------
76430
SQL>
4.3 在用用户tang 查询表
SQL> select count(1) from t10;
COUNT(1)
----------
76430
4.4 查询子游标记录
SQL>select sql_id,child_number,sql_text,parse_calls,plan_hash_value,loads from v$sql
where sql_text='select count(1) from t10';
SQL_ID CHILD_NUMBER SQL_TEXT PARSE_CALLS PLAN_HASH_VALUE LOADS
-----------------------------------------------------------------------
1 9z6r9gcz6gnmz 0 select count(1) from t10 3 1331550546 1
2 9z6r9gcz6gnmz 1 select count(1) from t10 2 1331550546 1
3 9z6r9gcz6gnmz 2 select count(1) from t10 2 1331550546 1
SQL_ID 相同,即说明是使用了同一个父游标,用子游标来区分不同属性的相同SQL
CHILD_NUMBER:这个字段不同,说明oracle知道这是3个用户下的相同SQL语句
LOADS:都做了1次硬解析,说明oracle知道这是3个不完全相同的SQL语句
select sql_id,child_number,child_address,sql_text
from v$sql where sql_text='select count(1) from t10';
SQL_ID CHILD_NUMBER CHILD_ADDRESS SQL_TEXT
1 9z6r9gcz6gnmz 0 00000002AF6653C0 select count(1) from t10
2 9z6r9gcz6gnmz 1 00000002AF778630 select count(1) from t10
3 9z6r9gcz6gnmz 2 00000002AFD6C328 select count(1) from t10
CHILD_ADDRESS 值不相同,即3个子游标的不同入口地址。
---------------------------------------------------------------------------------------------
5.演示ACS(adaptiver cursor sharing)的效果。<br>
5.1 建立测试环境数据
SQL> drop table t purge;
Table dropped.
SQL> create table t as select case when rownum<=100 then 1 else 2 end as id from dual connect by rownum<1000000;
Table created.
SQL> create index idx_t_id on t(id);
Index created.
5.2 对表进行统计分析(ACS 要有直方图信息)
SQL> execute dbms_stats.gather_table_stats(user,'T',method_opt=>'for all columns size 2');
PL/SQL procedure successfully completed.
SQL> set autotrace off;
SQL> select id,count(0) from t group by id;
ID COUNT(0)
---------- ----------
1 100
2 999899
SQL> set autot trace exp;
SQL> select count(0) from t where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 1700799834
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX RANGE SCAN| IDX_T_ID | 181 | 543 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=1)
SQL> select count(0) from t where id=2;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 433 (3)| 00:00:06 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | TABLE ACCESS FULL| T | 999K| 2928K| 433 (3)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=2)
SQL>
从上面两个执行计划可以看出,两个执行计划使用了ACS,走了不同的执行计划;
5.3 使用绑定变量执行SQL,并查看不同变量时的变化
SQL> alter session set sql_trace=true;
Session altered.
SQL> alter session set tracefile_identifier='tang'
2 ;
Session altered.
SQL> var v_num number;
SQL> execute :v_num:=2;
PL/SQL procedure successfully completed.
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
999899
SQL> execute :v_num:=1;
PL/SQL procedure successfully completed.
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
100
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
100
SQL> alter session set sql_trace=false;
Session altered.
SQL> select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
D:\APP\ORACLE\diag\rdbms\orcl\orcl\trace\orcl_ora_5952_tang.trc
SQL>
跟踪文件如下:
5.3.1 定义变量为2 时的执行计划:
SQL ID: 9qvxqz87xn8vt Plan Hash: 0
BEGIN :v_num:=2; END;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 0 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
--执行绑定变量SQL,我们可以看执行计划为全表扫描,这是没有问题的,因为数据比较倾斜,
id为2的记录很多,之前的测试也是全表扫描
--但是我们要注意,这个SQL语句执行了2次,也就是全表扫描的方式执行了2次,
也就是当值为1的第一次执行走的是全表扫描。
5.3.2 定义变量为1 时, 已重新进行了一个硬分析。走的也是全表扫描,这点和想象的不一样。
感觉很奇怪,
SQL ID: fdp2j9cdw8pc5 Plan Hash: 0
BEGIN :v_num:=1; END;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 0 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
再看一下是否有错:
从下面的测试中看到,不管我使用变量 1或者2 ,走的都是全表扫描。并没有走索引。
查看 is_bind_sensitive
表示游标是否对绑定变量敏感。数值如果为Y,表示当绑定变量的数值发生变化后,
优化器有可能会产生一个不同的执行计划,简单说就是ACS生效了。
我这里就是因为这个,一直是N,如下:
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive,is_bind_aware from v$sql where sql_text like 'select count(0) from t where id=:v_n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 0 1
0 N N Y
SQL> exec :n :=2;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
999899
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 1 1
1527 N N Y
SQL> exec :n :=2;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
999899
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 2 1
3054 N N Y
SQL>
SQL> exec :n :=1;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
100
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 3 1
4581 N N Y
SQL>
2.用示例演示一次硬分析(hard parse)和一次软分析(soft parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>
3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>
5.演示ACS(adaptiver cursor sharing)的效果。<br>
==================================================================================
1.用示例说明绑定变量的应用领域是OLTP而不是OLAP。<br>
答:
1.1 示例说明
SQL> drop table t1 purge;
Table dropped.
SQL> create table t1 as select * from dba_objects;
Table created.
SQL> alter session set tracefile_identifier='bind_var';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL> begin
2 for i in 1..100 loop
3 execute immediate 'select * from t1 where object_id=:i' using i;
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> alter session set sql_trace=false;
Session altered.
SQL> select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %';
select sql_text,pase_calls,loads,executions from v$sql where sql_text like 'select * from t1 where %'
*
ERROR at line 1:
ORA-00904: "PASE_CALLS": invalid identifier
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from t1%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
----------- ---------- ---- ----------
select * from t1 where object_id=:i 1 1 100
从上面的查询中,可以看到,在重复执行了100次的查询中,有1次的硬解析,
1.2 下面再进行一个非绑定变量的SQL 执行情况:
SQL> alter session set sql_trace=true; 启动trace功能
Session altered.
SQL> begin
for i in 1..100 loop
execute immediate 'select * from T where object_id='||i;
end loop;
end;
/
PL/SQL procedure successfully completed.
我们对一条sql执行了100次没有采用绑定变量技术,oracle对这条sql要硬解析100次,执行100次,CPU的消耗就有了100次。
SQL> alter session set sql_trace=false; 关闭trace功能
Session altered.
LEO1@LEO1> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select * from T1 where %' order by 1;
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
---------------------- ---------- ---------- ----------
select * from t1 where object_id=1 1 1 1
....
select * from t1 where object_id=100 1 1 1
100 rows selected.
SQL>
再来查看一下跟踪文件:
1.3 使用绑定变量跟踪部分:
D:\app\oracle\diag\rdbms\orcl\orcl\trace>tkprof orcl_ora_5528_bind_var.trc out_b
ind.log
TKPROF: Release 11.2.0.3.0 - Development on 星期四 12月 5 17:58:35 2013
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
SQL ID: 28gj7tsy13xq8 Plan Hash: 3617692013
select *
from
t1 where object_id=:i
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 100 0.01 0.00 0 1 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 101 0.01 0.00 0 1 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=3 us cost=305 size=2484 card=12)
********************************************************************************
1.4 没使用绑定变量跟踪部分:
begin
for i in 1..100 loop
execute immediate 'select * from t1 where object_id='||i;
end loop;
end;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.01 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.02 0 0 0 1
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
SQL ID: 9vx4vjbr7qrnn Plan Hash: 2586623307
SELECT /* OPT_DYN_SAMP */ /*+ ALL_ROWS IGNORE_WHERE_CLAUSE
NO_PARALLEL(SAMPLESUB) opt_param('parallel_execution_enabled', 'false')
NO_PARALLEL_INDEX(SAMPLESUB) NO_SQL_TUNE */ NVL(SUM(C1),:"SYS_B_0"),
NVL(SUM(C2),:"SYS_B_1")
FROM
(SELECT /*+ IGNORE_WHERE_CLAUSE NO_PARALLEL("T1") FULL("T1")
NO_PARALLEL_INDEX("T1") */ :"SYS_B_2" AS C1, CASE WHEN "T1"."OBJECT_ID"=
:"SYS_B_3" THEN :"SYS_B_4" ELSE :"SYS_B_5" END AS C2 FROM "TANG"."T1"
SAMPLE BLOCK (:"SYS_B_6" , :"SYS_B_7") SEED (:"SYS_B_8") "T1") SAMPLESUB
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 100 0.00 0.01 0 0 0 0
Execute 100 0.00 0.00 0 0 0 0
Fetch 100 0.18 0.16 0 6900 0 100
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 300 0.18 0.17 0 6900 0 100
Misses in library cache during parse: 1
Misses in library cache during execute: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 2)
Number of plan statistics captured: 3
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
1 1 1 SORT AGGREGATE (cr=69 pr=0 pw=0 time=1701 us)
4452 4452 4452 TABLE ACCESS SAMPLE T1 (cr=69 pr=0 pw=0 time=4608 us cost=19 size=128650 card=5146)
********************************************************************************
SQL ID: d44dqxf5hgz0j Plan Hash: 3617692013
select *
from
t1 where object_id=1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 1 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 1 0 0
Misses in library cache during parse: 1
Optimizer mode: ALL_ROWS
Parsing user id: 84 (recursive depth: 1)
Number of plan statistics captured: 1
Rows (1st) Rows (avg) Rows (max) Row Source Operation
---------- ---------- ---------- ---------------------------------------------------
0 0 0 TABLE ACCESS FULL T1 (cr=0 pr=0 pw=0 time=2 us cost=305 size=2484 card=12)
********************************************************************************
从上面使用了绑定变量的方法,可以看到,执行100次,只有一次硬解析。
而非绑定变量方法,每一次的SQL,都是独立解析及运行的。CPU的消耗也可以看到两者的差异。
1.4.绑定变量的SQL代码优化,主要是减少了SQL 的硬解析。
1.5 在OLTP 架构中,
1.5.1 SQL 简单而非常相似,并且结果集非常小,不同的只是谓语部分。所以这种情况下,执行计划都是一样的。
在执行计划都几乎不变的情况下。ORACLE使用变量来代替谓词,使用同一个执行计划,是非常合理的。
1.5.2 SQL 重复率很高,或者只是谓词条件不同而已;
1.5.3 SQL 语句执行条件多,条数越多,CPU的消耗就大,这种情况下,减少硬解析就越有意义了。
1.6 在OLAP 架构中
1.6.1 SQL 执行的重复率低,大部分都只是批量,定时加载,
1.6.2 数据聚合操作频繁;
1.6.3 SQL 语句执行条数少,SQL 硬解析对系统性能影响较小,更多的瓶颈是IO,
1.6.3 分区表的查询,相对也不太适合绑定变量技术.
综上所述,所以说OLAP不适合使用绑定变量。
---------------------------------------------------------------------------------------------
2.用示例演示一次硬分析(hard parse)和一次软分析(soft parse),以及一次更软的分析(softer soft parse),并对给出演示结果。<br>
ORACLE SQL 执行过程:
数据库端收到一个sql 请求后,会建立一个进程,与用户进程组成一个会话,在pga区处理sql 请求。
然后开始访问sga的sharl pool,并解析SQL,生成执行计划;
如果一条SQL 在share pool中已经存在,那么ORACLE 只需奖已存在的执行计划应用到当前SQL上,去访问数据即可。这种情况称之为软解析(SOFT PARSE);
如果在共享汇中没有找到SQL的执行计划,ORACLE就会对SQL 进行: 语法解析,语义解析,生成执行计划等动作,这些解析步骤就总称为硬解析(HARD PARSE);
而这些解析步骤是比较消耗资源的。
还有另外一种解析是:缓存游标信息,后续的SQL不用再去打开一个新的cursor,而是直接去share pool 中找到已查询过的数据,这样就更省资源,
成为更软的解析(SOFTER SOFT PARSE).
2.1 演示数据准备及第一次执行效果
SQL> drop table t2 purge;
Table dropped.
SQL> create table t2 as select * from dba_objects;
Table created.
SQL> select count(0) from t2;
COUNT(0)
----------
76429
查询SQL 运行情况
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 1 1 1
可以看到总解析 1次;硬解析 1次,执行次数 1 次;
下面我们再执行一次:
2.2 第二次执行效果
SQL> select count(0) from t2;
COUNT(0)
----------
76429
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 2 1 2
这时可以看到总解析 2次;硬解析 1次,执行次数 2 次; 第2次没有进行硬解析,就是因为SQL 放在
SHARED_POOL中,进行了一次软解析;
2.3 我们再把SHARED_POOL清空,看看效果:
SQL> alter system flush shared_pool;
System altered.
SQL> select count(0) from t2;
COUNT(0)
----------
76429
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select count(0) from t2' order by
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
--------------------------------- ----------- ---------- ----------
select count(0) from t2 1 1 1
这时,ORACLE 认为是一条新的SQL了。所以又有一次硬解析。
2.4 softer_soft_parse 会话对游标的缓存
SQL> alter session set tracefile_identifier='tang';
Session altered.
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set events '10046 trace name context forever,level 12';
Session altered.
SQL> alter session set sql_trace=true;
Session altered.
SQL>
SQL> show parameter session_cached_cursors;
NAME TYPE
------------------------------------ ---------------------------------
VALUE
------------------------------
session_cached_cursors integer
50
SQL> set linesize 100;
SQL> select 'STAT-'||name,value from v$sysstat where name like '%parse%' or name like'%cursor%'
2 union all select 'LATCH-'||name,gets from v$latch where name = 'shared pool';
'STAT-'||NAME VALUE
---------- ------------------------------
STAT-opened cursors cumulative 10897
STAT-opened cursors current 28
STAT-pinned cursors current 12
STAT-session cursor cache hits 12908
STAT-session cursor cache count 882
STAT-cursor authentications 237
STAT-parse time cpu 91
STAT-parse time elapsed 224
STAT-parse count (total) 1752
STAT-parse count (hard) 1271
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 98158
13 rows selected.
SQL>
SQL> select count(0) from t10;
COUNT(0)
----------
76432
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'select count(0) from t10';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' un
ets from v$latch where name = 'shared pool';
NAME VALUE
----------------------------------------
STAT-opened cursors cumulative 21492
STAT-opened cursors current 29
STAT-pinned cursors current 11
STAT-session cursor cache hits 23418
STAT-session cursor cache count 1033
STAT-cursor authentications 262
STAT-parse time cpu 96
STAT-parse time elapsed 230
STAT-parse count (total) 1887
STAT-parse count (hard) 1290
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 118288
13 rows selected.
SQL>
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set session_cached_cursors=0;
Session altered.
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
ets from v$latch where name = 'shared pool';
NAME VALUE
-------------------------------------------
STAT-opened cursors cumulative 26250
STAT-opened cursors current 28
STAT-pinned cursors current 11
STAT-session cursor cache hits 28300
STAT-session cursor cache count 1671
STAT-cursor authentications 363
STAT-parse time cpu 148
STAT-parse time elapsed 300
STAT-parse count (total) 2855
STAT-parse count (hard) 1620
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 153871
13 rows selected.
SQL> select count(0) from t10;
COUNT(0)
----------
76432
SQL> begin
2 for i in 1..10000 loop
3 execute immediate 'select count(0) from t10';
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL>
SQL> select substr('STAT-'||name,1,50) as name,value from v$sysstat where name like '%parse%' or name like'%cursor%' union all
ets from v$latch where name = 'shared pool';
NAME VALUE
----------------------------------------
STAT-opened cursors cumulative 39364
STAT-opened cursors current 30
STAT-pinned cursors current 10
STAT-session cursor cache hits 34321
STAT-session cursor cache count 1912
STAT-cursor authentications 442
STAT-parse time cpu 184
STAT-parse time elapsed 337
STAT-parse count (total) 13302
STAT-parse count (hard) 1814
STAT-parse count (failures) 0
STAT-parse count (describe) 0
LATCH-shared pool 177749
13 rows selected.
SQL>
---------------------------------------------------------------------------------------------
3.用示例演示一次分析,多次执行的示例,并对给出演示结果。<br>
3.1 使用不绑定变量,执行3次不同的SQL,是各自进行硬分析的:
SQL> alter system flush shared_pool;
System altered.
SQL> select object_id from t10 where object_id=100;
OBJECT_ID
----------
100
SQL> select object_id from t10 where object_id=200;
OBJECT_ID
----------
200
SQL> select object_id from t10 where object_id=300;
OBJECT_ID
----------
300
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%'
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
----------- ---------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=100 1 1 1
SQL>
3.2 使用绑定变量
SQL> var vid number;
SQL> execute :vid:=100;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id:=vid;
select object_id from t10 where object_id:=vid
*
ERROR at line 1:
ORA-00920: invalid relational operator
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
100
SQL> execute :vid:=150;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
150
SQL> execute :vid:=160;
PL/SQL procedure successfully completed.
SQL> select object_id from t10 where object_id=:vid;
OBJECT_ID
----------
160
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
---------------------- ----------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=:vid 3 1 3
select object_id from t10 where object_id=100 1 1 1
SQL>
从上面最后的查询看到,最后一次使用变量的方式执行的3次SQL,只进行了一次硬分析
Oracle认为这3条SQL是完全一样的(除了谓词部分)所以第一次执行的时候做一次硬解析后续2条SQL只做软解析,比上一个少了2次硬解析,性能提高
绑定变量2
SQL> begin
2 for i in 1..3 loop
3 execute immediate 'select object_id from t10 where object_id=:i' using i;
4 end loop;
5 end;
6 /
PL/SQL procedure successfully completed.
SQL> select sql_text,parse_calls,loads,executions from v$sql where sql_text like 'select object_id from t10%';
SQL_TEXT PARSE_CALLS LOADS EXECUTIONS
-------------------------------------------- ----------- ---------- ----------
select object_id from t10 where object_id=300 1 1 1
select object_id from t10 where object_id=200 1 1 1
select object_id from t10 where object_id=:i 1 1 3
select object_id from t10 where object_id=:vid 3 1 3
select object_id from t10 where object_id=100 1 1 1
SQL>
Oracle认为这3条SQL是完全一样的(除了谓词部分),和上面不同的是只做了1次硬解析没有软解析,反复执行了3次。
我们做了一个循环,用leo变量代替谓词常量,每次都用相同的执行计划(执行计划不需要重新生成),只是改变一下常量值而已。
上面3种执行方法,从上面的查询中,很好的看出各自的不同,优点最明显的就是最后一次的SQL.
---------------------------------------------------------------------------------------------
4.演示一个父游标产生3个子游标的示例,并分别说明每个子游标产生的原因。<br>
4.1 把用户TANG.10 的查询权限赋给 test,scott;
SQL> grant select on t10 to test;
Grant succeeded
SQL> grant select on t10 to scott;
Grant succeeded
SQL>
4.2 在test,scott 用户下各建立T10表;
C:\Users\Administrator>sqlplus test/test@orcl
SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:27:31 2013
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table t10 as select * from tang.t10;
Table created.
SQL> select count(1) from t10;
COUNT(1)
----------
76430
SQL>
C:\Users\Administrator>sqlplus scott/scott@orcl
SQL*Plus: Release 11.2.0.1.0 Production on Fri Dec 6 17:30:24 2013
Copyright (c) 1982, 2010, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table t10 as select * from tang.t10;
Table created.
SQL> select count(1) from t10;
COUNT(1)
----------
76430
SQL>
4.3 在用用户tang 查询表
SQL> select count(1) from t10;
COUNT(1)
----------
76430
4.4 查询子游标记录
SQL>select sql_id,child_number,sql_text,parse_calls,plan_hash_value,loads from v$sql
where sql_text='select count(1) from t10';
SQL_ID CHILD_NUMBER SQL_TEXT PARSE_CALLS PLAN_HASH_VALUE LOADS
-----------------------------------------------------------------------
1 9z6r9gcz6gnmz 0 select count(1) from t10 3 1331550546 1
2 9z6r9gcz6gnmz 1 select count(1) from t10 2 1331550546 1
3 9z6r9gcz6gnmz 2 select count(1) from t10 2 1331550546 1
SQL_ID 相同,即说明是使用了同一个父游标,用子游标来区分不同属性的相同SQL
CHILD_NUMBER:这个字段不同,说明oracle知道这是3个用户下的相同SQL语句
LOADS:都做了1次硬解析,说明oracle知道这是3个不完全相同的SQL语句
select sql_id,child_number,child_address,sql_text
from v$sql where sql_text='select count(1) from t10';
SQL_ID CHILD_NUMBER CHILD_ADDRESS SQL_TEXT
1 9z6r9gcz6gnmz 0 00000002AF6653C0 select count(1) from t10
2 9z6r9gcz6gnmz 1 00000002AF778630 select count(1) from t10
3 9z6r9gcz6gnmz 2 00000002AFD6C328 select count(1) from t10
CHILD_ADDRESS 值不相同,即3个子游标的不同入口地址。
---------------------------------------------------------------------------------------------
5.演示ACS(adaptiver cursor sharing)的效果。<br>
5.1 建立测试环境数据
SQL> drop table t purge;
Table dropped.
SQL> create table t as select case when rownum<=100 then 1 else 2 end as id from dual connect by rownum<1000000;
Table created.
SQL> create index idx_t_id on t(id);
Index created.
5.2 对表进行统计分析(ACS 要有直方图信息)
SQL> execute dbms_stats.gather_table_stats(user,'T',method_opt=>'for all columns size 2');
PL/SQL procedure successfully completed.
SQL> set autotrace off;
SQL> select id,count(0) from t group by id;
ID COUNT(0)
---------- ----------
1 100
2 999899
SQL> set autot trace exp;
SQL> select count(0) from t where id=1;
Execution Plan
----------------------------------------------------------
Plan hash value: 1700799834
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | INDEX RANGE SCAN| IDX_T_ID | 181 | 543 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=1)
SQL> select count(0) from t where id=2;
Execution Plan
----------------------------------------------------------
Plan hash value: 2966233522
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 | 433 (3)| 00:00:06 |
| 1 | SORT AGGREGATE | | 1 | 3 | | |
|* 2 | TABLE ACCESS FULL| T | 999K| 2928K| 433 (3)| 00:00:06 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("ID"=2)
SQL>
从上面两个执行计划可以看出,两个执行计划使用了ACS,走了不同的执行计划;
5.3 使用绑定变量执行SQL,并查看不同变量时的变化
SQL> alter session set sql_trace=true;
Session altered.
SQL> alter session set tracefile_identifier='tang'
2 ;
Session altered.
SQL> var v_num number;
SQL> execute :v_num:=2;
PL/SQL procedure successfully completed.
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
999899
SQL> execute :v_num:=1;
PL/SQL procedure successfully completed.
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
100
SQL> select count(0) from t where id=:v_num;
COUNT(0)
----------
100
SQL> alter session set sql_trace=false;
Session altered.
SQL> select value from v$diag_info where name='Default Trace File';
VALUE
--------------------------------------------------------------------------------
D:\APP\ORACLE\diag\rdbms\orcl\orcl\trace\orcl_ora_5952_tang.trc
SQL>
跟踪文件如下:
5.3.1 定义变量为2 时的执行计划:
SQL ID: 9qvxqz87xn8vt Plan Hash: 0
BEGIN :v_num:=2; END;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 0 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
--执行绑定变量SQL,我们可以看执行计划为全表扫描,这是没有问题的,因为数据比较倾斜,
id为2的记录很多,之前的测试也是全表扫描
--但是我们要注意,这个SQL语句执行了2次,也就是全表扫描的方式执行了2次,
也就是当值为1的第一次执行走的是全表扫描。
5.3.2 定义变量为1 时, 已重新进行了一个硬分析。走的也是全表扫描,这点和想象的不一样。
感觉很奇怪,
SQL ID: fdp2j9cdw8pc5 Plan Hash: 0
BEGIN :v_num:=1; END;
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 1
Fetch 0 0.00 0.00 0 0 0 0
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 2 0.00 0.00 0 0 0 1
Misses in library cache during parse: 0
Optimizer mode: ALL_ROWS
Parsing user id: 84
********************************************************************************
再看一下是否有错:
从下面的测试中看到,不管我使用变量 1或者2 ,走的都是全表扫描。并没有走索引。
查看 is_bind_sensitive
表示游标是否对绑定变量敏感。数值如果为Y,表示当绑定变量的数值发生变化后,
优化器有可能会产生一个不同的执行计划,简单说就是ACS生效了。
我这里就是因为这个,一直是N,如下:
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive,is_bind_aware from v$sql where sql_text like 'select count(0) from t where id=:v_n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 0 1
0 N N Y
SQL> exec :n :=2;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
999899
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 1 1
1527 N N Y
SQL> exec :n :=2;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
999899
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 2 1
3054 N N Y
SQL>
SQL> exec :n :=1;
PL/SQL procedure successfully completed.
SQL> select count(*) from t where id=:n;
COUNT(*)
----------
100
SQL> select sql_id,child_number,executions,loads,buffer_gets,is_bind_sensitive as "bind_sensi",is_bind_aware as "
re" from v$sql where sql_text like 'select count(*) from t where id=:n';
SQL_ID CHILD_NUMBER EXECUTIONS LOADS
--------------------------------------- ------------ ---------- ----------
BUFFER_GETS bin bin bin
----------- --- --- ---
3fvuhx84ba43x 0 3 1
4581 N N Y
SQL>