绑定变量窥探和直方图

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


 

原文地址:https://www.cnblogs.com/zhaoyangjian724/p/3797951.html