绑定变量窥视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语句共享