本文章主要研究cursor_sharing参数不同设置,histograms收集与否对SQL version count 产生的影响。
一、cursor_sharing参数与SQL version count
数据库研究版本:
引用
SQL> select * from v$version where rownum<2;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
创建测试脚本
引用
create table t1( i number, j number, k number);
begin
for i in 1..10000 loop
insert into t1 values( i, i, i);
end loop;
end;
/
将cursor_sharing参数改为similar,可以看出谓词连接采用>(还有>, <, >=, <=, LIKE)时,SQL在共享parent cursor时不能共享child cursor
引用
SQL> alter session set cursor_sharing=similar
2 ;
Session altered.
SQL> select count(*) from t1 where i > 10;
COUNT(*)
----------
9990
SQL>select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
1
SQL> select count(*) from t1 where i > 20;
COUNT(*)
----------
9980
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
2
SQL> select count(*) from t1 where i > 30;
COUNT(*)
----------
9970
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
3
将谓词连接改为=时,SQL在共享parent cursor时能共享child cursor
引用
SQL> select count(*) from t1 where i=100;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
3
select count(*) from t1 where i=:"SYS_B_0"
1
SQL> select count(*) from t1 where i=200;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
3
select count(*) from t1 where i=:"SYS_B_0"
1
将cursor_sharing参数改为force,我们看到cursor实现了共享。
引用
SQL> alter session set cursor_sharing=force;
Session altered.
SQL> select count(*) from t1 where i > 40;
COUNT(*)
----------
9960
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
4
select count(*) from t1 where i=:"SYS_B_0"
1
SQL> select count(*) from t1 where i > 50;
COUNT(*)
----------
9950
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
4
select count(*) from t1 where i=:"SYS_B_0"
1
进一步将cursor_sharing改为exact,cursor甚至不能在parent级别实现共享
引用
SQL> alter session set cursor_sharing=exact;
Session altered.
SQL> select count(*) from t1 where i > 70;
COUNT(*)
----------
9930
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
4
select count(*) from t1 where i >:"SYS_B_0"
1
select count(*) from t1 where i=:"SYS_B_0"
1
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > 70
1
SQL> select count(*) from t1 where i > 80;
COUNT(*)
----------
9920
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > :"SYS_B_0"
4
select count(*) from t1 where i >:"SYS_B_0"
1
select count(*) from t1 where i=:"SYS_B_0"
1
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i > 80
1
select count(*) from t1 where i > 70
1
二、cursor_sharing参数histogram与SQL version count
在table t1所有列上收集直方图(J列除外)
引用
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'sys',tabname=>'t1',method_opt=>'FOR ALL COLUMNS SIZE 10');
PL/SQL procedure successfully completed.
SQL> exec DBMS_STATS.GATHER_TABLE_STATS(ownname=>'sys',tabname=>'t1',method_opt=>'FOR COLUMNS J SIZE 1');
PL/SQL procedure successfully completed.
SQL> select COLUMN_NAME,NUM_BUCKETS,HISTOGRAM from dba_tab_columns where OWNER='SYS' and TABLE_NAME='T1';
COLUMN_NAME NUM_BUCKETS HISTOGRAM
------------------------------ ----------- ---------------
I 10 HEIGHT BALANCED
J 1 NONE
K 10 HEIGHT BALANCED
将cursor_sharing改为similar,发现在有直方图的列上不能实现child cursor共享。
引用
SQL> alter session set cursor_sharing = similar;
Session altered.
SQL> select count(*) from t1 where i = 10;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where i = 20;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
2
SQL> select count(*) from t1 where i = 30;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
3
SQL> alter system flush shared_pool;
System altered.
SQL> select count(*) from t1 where j = 10;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where j = :"SYS_B_0"
1
SQL> select count(*) from t1 where j = 20;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where j = :"SYS_B_0"
1
SQL> select count(*) from t1 where j = 30;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where j = :"SYS_B_0"
1
将cursor_sharing改为force时,无论在有直方图或无直方图的列上都实现了游标共享。
引用
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set cursor_sharing=force;
Session altered.
SQL> select count(*) from t1 where i = 10;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where i = 20;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where i = 30;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where j = 10;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where j = 20;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
select count(*) from t1 where i = :"SYS_B_0"
1
SQL> select count(*) from t1 where j = 30;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :"SYS_B_0"
1
select count(*) from t1 where i = :"SYS_B_0"
1
将cursor_sharing改为exact,并使用绑定变量,经测试实现了游标共享,但是需要注意的是如果使用绑定变量由于BIND PEEKING,会导致执行计划不稳定
引用
SQL> alter system flush shared_pool;
System altered.
SQL> alter session set cursor_sharing=exact;
Session altered.
SQL> variable i number;
SQL> exec :i:=10
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where i = :i;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :i
1
SQL> exec :i:=20
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where i = :i;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :i
1
SQL> exec :i:=0
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where i = :i;
COUNT(*)
----------
0
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :i
1
SQL> variable j number;
SQL> exec :j:=10
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where j = :j;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where i = :i
1
SQL> exec :j:=100
PL/SQL procedure successfully completed.
SQL> select count(*) from t1 where j = :j;
COUNT(*)
----------
1
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where j = :j
1
select count(*) from t1 where i = :i
1
SQL> exec :j:=1000
PL/SQL procedure successfully completed.
SQL> select sql_text,version_count from v$sqlarea where
2 sql_text like 'select count(*) from t1 where%';
SQL_TEXT
--------------------------------------------------------------------------------
VERSION_COUNT
-------------
select count(*) from t1 where j = :j
1
select count(*) from t1 where i = :i
1