绑定变量窥视cbo的一个附属功能,关闭他不会影响是用cbo还是rbo,就算关闭了绑定变量窥视,cbo还是会利用别的统计信息(num_distinct,density等)来评估cost和cardinality,只
是无法使用直方图信息而已:
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND x.ksppinm LIKE '%&par%'; 2 3 4 5 6
Enter value for par: peek_user
old 6: AND x.ksppinm LIKE '%&par%'
new 6: AND x.ksppinm LIKE '%peek_user%'
NAME VALUE DESCRIB
------------------------------ -------------------- ------------------------------
_optim_peek_user_binds TRUE enable peeking of user binds
当前开启绑定变量,开始测试:
SQL> alter system flush shared_pool;
System altered.
SQL> select sql_text,sql_id,a.executions from v$sql a
where a.parsing_schema_name='SCOTT'
order by last_active_time desc; 2 3
no rows selected
SQL> variable n number;
SQL> exec :n := 7499;
PL/SQL procedure successfully completed.
SQL> select * from emp where empno = :n;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO DNAME
---------- --------------------------------------------------
7499 ALLEN SALESMAN 7698 20-FEB-81 1600 300
30 UFO
SQL> select sql_text,sql_id,a.executions from v$sql a
where a.parsing_schema_name='SCOTT'
order by last_active_time desc; 2 3
SQL_TEXT SQL_ID EXECUTIONS
------------------------------ ------------- ----------
select * from emp where empno 3vv0t64yn0wrm 1
= :n
BEGIN :n := 7499; END; 2u1u06mytpsha 1
SQL> exec :n := 7521;
PL/SQL procedure successfully completed.
SQL> select * from emp where empno = :n;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO DNAME
---------- --------------------------------------------------
7521 WARD SALESMAN 7698 22-FEB-81 1250 500
30 UFO
查看执行次数:
SQL> select sql_text,sql_id,a.executions from v$sql a
where a.parsing_schema_name='SCOTT'
order by last_active_time desc; 2 3
SQL_TEXT SQL_ID EXECUTIONS
------------------------------ ------------- ----------
select * from emp where empno 3vv0t64yn0wrm 2
= :n
BEGIN :n := 7521; END; 9b4dm4tp4k58q 1
BEGIN :n := 7499; END; 2u1u06mytpsha 1
此时说明代码完全共享
2.继续测试,关闭绑定变量窥探:
SQL> SQL> alter system set "_optim_peek_user_binds"=FALSE;
System altered.
Session altered.
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND x.ksppinm LIKE '%&par%'; 2 3 4 5 6
Enter value for par: peek_user
old 6: AND x.ksppinm LIKE '%&par%'
new 6: AND x.ksppinm LIKE '%peek_user%'
NAME
----------
VALUE
------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------
DESCRIB
------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------
_optim_pee
k_user_bin
ds
FALSE
enable peeking of user binds
此时绑定变量已经关闭:
SQL> alter system flush shared_pool;
System altered.
SQL> exec :n := 7698;
PL/SQL procedure successfully completed.
SQL> select * from emp where empno = :n;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO DNAME
---------- --------------------------------------------------
7698 BLAKE MANAGER 7839 01-MAY-81 2850
30 UFO
SQL> exec :n := 7654;
PL/SQL procedure successfully completed.
SQL> select * from emp where empno = :n;
EMPNO ENAME JOB MGR HIREDATE SAL COMM
---------- ---------- --------- ---------- --------- ---------- ----------
DEPTNO DNAME
---------- --------------------------------------------------
7654 MARTIN SALESMAN 7698 28-SEP-81 1250 1400
30 UFO
查看执行情况:
SQL> select sql_text,sql_id,a.executions from v$sql a
where a.parsing_schema_name='SCOTT' 2 ;
SQL_TEXT SQL_ID EXECUTIONS
------------------------------ ------------- ----------
select * from emp where empno 3vv0t64yn0wrm 2
= :n
BEGIN :n := 7698; END; gp8mhcr67r352 1
BEGIN :n := 7654; END; apkbvs4zq7cnh 1
SQL> select a.sql_text,a.sql_id,a.executions,a.version_count from v$sqlarea a where sql_id='3vv0t64yn0wrm';
SQL_TEXT SQL_ID EXECUTIONS VERSION_COUNT
------------------------------ ------------- ---------- -------------
select * from emp where empno 3vv0t64yn0wrm 3 1
= :n
SQL>
select a.sql_text,a.sql_id,a.executions,a.child_number from v$sql a where sql_id='3vv0t64yn0wrm';SQL>
SQL_TEXT SQL_ID EXECUTIONS CHILD_NUMBER
------------------------------ ------------- ---------- ------------
select * from emp where empno 3vv0t64yn0wrm 3 0
= :n
说明关闭绑定变量窥探,不会影响SQL语句的共享,关闭绑定变量窥探,Oracle就不能利用直方图信息了。
继续测试关闭绑定变量窥探,对Oracle执行计划的影响?
先打开绑定变量窥探:
SQL> SELECT x.ksppinm NAME, y.ksppstvl VALUE, x.ksppdesc describ
FROM SYS.x$ksppi x, SYS.x$ksppcv y
WHERE x.inst_id = USERENV ('Instance')
AND y.inst_id = USERENV ('Instance')
AND x.indx = y.indx
AND x.ksppinm LIKE '%&par%'; 2 3 4 5 6
Enter value for par: peek_user
old 6: AND x.ksppinm LIKE '%&par%'
new 6: AND x.ksppinm LIKE '%peek_user%'
NAME
--------------------------------------------------------------------------------
VALUE
--------------------------------------------------------------------------------
DESCRIB
--------------------------------------------------------------------------------
_optim_peek_user_binds
TRUE
enable peeking of user binds
SQL> begin
2 for i in 1 .. 10000
3 loop
4 insert into test values(1,'a1'||i);
5 commit;
6 end loop;
7 end;
8 /
SQL> insert into test values(2,'a');
1 row created.
SQL> commit;
Commit complete.
SQL> select id,count(*) from test
2 group by id;
ID COUNT(*)
---------- ----------
1 10000
2 1
SQL> BEGIN
DBMS_STATS.GATHER_TABLE_STATS(ownname => 'TEST',
tabname => 'TEST',
estimate_percent => 100,
method_opt => 'for all columns size skewonly',
no_invalidate => FALSE,
degree => 8,
cascade => TRUE);
END;
2 3 4 5 6 7 8 9 10
11 /
PL/SQL procedure successfully completed.
SQL> variable n number;
SQL> exec :n := 2;
PL/SQL procedure successfully completed.
SQL> select * from test where id = :n;
ID NAME
---------- ----------
2 a
SQL> select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------
SQL_ID 14nw6f8vtgsz7, child number 0
-------------------------------------
select * from test where id = :n
Plan hash value: 2624864549
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 14 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | TEST_IDX1 | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=:N)
19 rows selected.
返回一条记录走的索引扫描
SQL> exec :n := 1;
PL/SQL procedure successfully completed.
SQL> select * from test where id = :n;
SQL> select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------
SQL_ID 14nw6f8vtgsz7, child number 0
-------------------------------------
select * from test where id = :n
Plan hash value: 2624864549
-----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| TEST | 1 | 14 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | TEST_IDX1 | 1 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("ID"=:N)
19 rows selected.
走的还是索引扫描,充分说明Oracle在处理带有绑定变量的SQL时候,只会在硬解析的时候才会“窥探”一下SQL中绑定变量的值,然后会根据窥探到的值来决定整个SQL的执行计划
。
关闭绑定变量窥探:
SQL> alter system set "_optim_peek_user_binds"=FALSE;
System altered.
SQL> alter system flush shared_pool;
System altered.
SQL> variable n number;
SQL> exec :n := 2;
PL/SQL procedure successfully completed.
SQL> select * from test where id = :n;
ID NAME
---------- ----------
2 a
SQL> select * from table(dbms_xplan.display_cursor);
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------
SQL_ID 9tcmwpk23vu2y, child number 0
-------------------------------------
select * from test where id = :n
Plan hash value: 1357081020
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 9 (100)| |
|* 1 | TABLE ACCESS FULL| TEST | 5001 | 70014 | 9 (0)| 00:00:01 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ID"=:N)
18 rows selected.
此时走了全表扫描,由于关闭了绑定变量窥探,无法利用直方图信息。
结论;
(1)不绑定变量的情况下对于列倾斜严重的情况,直方图可以提供最好的数据分布参考
(2)绑定变量窥视的情况下 可以利用到直方图,但是11g adaptive cursor sharing之前无法区别绑定敏感游标和非敏感游标
(3)不窥视绑定变量的情况下虽然加载直方图信息,但实际计算cardinality不参考HISTOGRAM
开始绑定变量:使用直方图信息,然后会根据窥探到的值来决定整个SQL的执行计划。
不开始绑定变量:不使用直方图信息,Oracle不知道数据的分布情况
无论是否开始绑定变量窥探都不影响SQL语句共享