1. 程式人生 > 其它 >關於繫結變數窺探

關於繫結變數窺探

1.由於繫結變數窺探特性,對於後續生成的執行計劃,不僅套用了首次生成的執行計劃,而且執行計劃中的Row,Bytes,
Cost(%CPU)等都與首次生存執行計劃得值相同。儘管可以使用繫結變數解決OLTP系統中大量重複SQL的反覆解析的問題。但繫結變數
可能會導致SQL語句選擇非最佳的執行計劃。尤其是對於存在資料傾斜的列,且生成了直方圖更不宜於使用繫結變數。在Oracle 11g 中,自適應特性從一定程度解決了繫結變數窺探所導致的問題。

2.10g和11g環境下繫結變數窺探測試,11g中說是採用了自適用遊標,無論調整cursor_sharing,還是如下隱含引數,發現11g並沒有改進,存在疑問。但是繫結變數窺探的這個問題進測試是存在的。

alter system set "_optimizer_extended_cursor_sharing_rel"=none scope=spfile sid='*';
alter system set "_optimizer_extended_cursor_sharing"=none scope=spfile sid='*';
alter system set "_optimizer_adaptive_cursor_sharing"=false scope=spfile sid='*';

這個引數是用來告訴Oracle在什麼情況下可以共享遊標,即SQL重用。
Cursor_sharing引數有3個值可以設定:
1)、EXACT:通常來說,exact值是Oracle推薦的,也是預設的,它要求SQL語句在完全相同時才會重用,否則會被重新執行硬解析操作。
2)、SIMILAR:similar是在Oracle認為某條SQL語句的謂詞條件可能會影響到它的執行計劃時,才會被重新分析,否則將重用SQL。
3)、FORCE:force是在任何情況下,無條件重用SQL。
備註:上面所說的SQL重用,僅僅是指謂詞條件不同的SQL語句,實際上這樣的SQL基本上都在執行同樣的業務操作。

3、開啟與關閉
ACS預設情況下是開啟的,為了關閉ACS需要修改下列引數
alter system set "_optimizer_extended_cursor_sharing_rel"=none scope=spfile sid='*';
alter system set "_optimizer_extended_cursor_sharing"=none scope=spfile sid='*';
alter system set "_optimizer_adaptive_cursor_sharing"=false scope=spfile sid='*';
為了開啟ACS需要確保下列引數有效
alter system set "_optim_peek_user_binds" =true scope=spfile sid='*';
alter system set "_optimizer_adaptive_cursor_sharing" =TRUE scope=spfile sid='*';
alter system set "_optimizer_extended_cursor_sharing" =UDO scope=spfile sid='*';
alter system set "_optimizer_extended_cursor_sharing_rel" =SIMPLE scope=spfile sid='*';

在10g環境下測試

1、建立演示環境       
SQL> select * from v$version where rownum<2;    -->檢視當前資料庫版本                                         
                                                                                                              
BANNER                                                                                                        
---------------------------------------------------------------- Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bi conn SCOTT/SCOTT SQL> create table t(id,owner,object_id) as select rownum,owner,object_id from all_objects where rownum<=1000; SQL> alter table t add constraint t_pk primary key(id); begin dbms_stats.gather_table_stats( ownname=>'SCOTT', tabname=>'T', estimate_percent=>100, method_opt=>'for all columns size 1'); end; / 2、未使用繫結變數情形下SQL語句的執行計劃 檢視值的分佈情況 SQL> select count(id),count(distinct id),min(id),max(id) from t; COUNT(ID) COUNT(DISTINCTID) MIN(ID) MAX(ID) ---------- ----------------- ---------- ---------- 1000 1000 1 1000 SQL> select sum(object_id) from t where id<900; SUM(OBJECT_ID) -------------- 1513589 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID bz6h6fdsxgjka, child number 0 ------------------------------------- select sum(object_id) from t where id<900 Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | |* 2 | TABLE ACCESS FULL| T | 900 | 7200 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"<900) 19 rows selected. SQL> SQL> set linesize 200 pagesize 2000 SQL> select sum(object_id) from t where id<10; SUM(OBJECT_ID) -------------- 3012 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 6y2280pyvacfq, child number 0 ------------------------------------- select sum(object_id) from t where id<10 Plan hash value: 4270555908 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 9 | 72 | 3 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_PK | 9 | | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"<10) 20 rows selected. 3、使用繫結變數情形下的執行計劃 SQL> variable v_id number; SQL> exec :v_id:=900; PL/SQL procedure successfully completed. SQL> select sum(object_id) from t where id<:v_id; SUM(OBJECT_ID) -------------- 1513589 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 7qcp6urqh7d2j, child number 0 ------------------------------------- select sum(object_id) from t where id<:v_id Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | |* 2 | TABLE ACCESS FULL| T | 900 | 7200 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"<:V_ID) 19 rows selected. SQL> exec :v_id:=10; PL/SQL procedure successfully completed. SQL> select sum(object_id) from t where id<:v_id; SUM(OBJECT_ID) -------------- 3012 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------ SQL_ID 7qcp6urqh7d2j, child number 0 ------------------------------------- select sum(object_id) from t where id<:v_id Plan hash value: 2966233522 --------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | |* 2 | TABLE ACCESS FULL| T | 900 | 7200 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("ID"<:V_ID) 19 rows selected. SQL> alter system flush shared_pool; System altered. SQL> print v_id; V_ID ---------- 10 SQL> select round(avg(object_id)) from t where id<:v_id; ROUND(AVG(OBJECT_ID)) --------------------- 335 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT ------------------------------------------------------------------------------------------------------------------------------------------------------ SQL_ID 0bx53mgt4qqnt, child number 0 ------------------------------------- select round(avg(object_id)) from t where id<:v_id Plan hash value: 4270555908 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 9 | 72 | 3 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_PK | 9 | | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"<:V_ID) 20 rows selected. SQL> exec :v_id:=900; PL/SQL procedure successfully completed. SQL> select round(avg(object_id)) from t where id<:v_id; ROUND(AVG(OBJECT_ID)) --------------------- 1684 SQL> select * from table(dbms_xplan.display_cursor()); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 0bx53mgt4qqnt, child number 0 ------------------------------------- select round(avg(object_id)) from t where id<:v_id Plan hash value: 4270555908 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 8 | | | | 2 | TABLE ACCESS BY INDEX ROWID| T | 9 | 72 | 3 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | T_PK | 9 | | 2 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("ID"<:V_ID) 20 rows selected. SQL> drop table t purge; Table dropped.

在11g環境下測試

1、建立演示環境       
SQL> select * from v$version where rownum<2;    -->檢視當前資料庫版本                                         
                                                                                                              
BANNER                                                                                                        
----------------------------------------------------------------                                              
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
        
conn SCOTT/SCOTT
        
SQL> create table t(id,owner,object_id) as       -->建立測試表t                                               
  select rownum,owner,object_id from all_objects where rownum<=1000;                                       
                                                                                                              
SQL> alter table t add constraint t_pk primary key(id);  -->為表t新增主鍵                                     
                                                                                                              
 begin                                               -->收集統計資訊,此處未生成直方圖資訊                 
 dbms_stats.gather_table_stats(                                                                           
 ownname=>'SCOTT',                                                                                        
 tabname=>'T',                                                                                            
 estimate_percent=>100,                                                                                   
 method_opt=>'for all columns size 1');                                                                   
 end;                                                                                                     
 /                                                                                                        
22:43:14 SCOTT@zytrac1>select count(id),count(distinct id),min(id),max(id) from t;

 COUNT(ID) COUNT(DISTINCTID)    MIN(ID)    MAX(ID)
---------- ----------------- ---------- ----------
      1000              1000          1       1000
      
  
2、未使用繫結變數情形下SQL語句的執行計劃       
                                                                                                              
22:47:17 SCOTT@zytrac1>select sum(object_id) from t where id<900;

SUM(OBJECT_ID)
--------------
        451307

Elapsed: 00:00:00.00
22:47:27 SCOTT@zytrac1>select * from table(dbms_xplan.display_cursor()); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  bz6h6fdsxgjka, child number 0
-------------------------------------
select sum(object_id) from t where id<900

Plan hash value: 2966233522

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"<900)


19 rows selected.

Elapsed: 00:00:00.05
22:47:32 SCOTT@zytrac1>select sum(object_id) from t where id<10;

SUM(OBJECT_ID)
--------------
           261

Elapsed: 00:00:00.00
22:48:20 SCOTT@zytrac1>select * from table(dbms_xplan.display_cursor());

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  6y2280pyvacfq, child number 0
-------------------------------------
select sum(object_id) from t where id<10

Plan hash value: 4270555908

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("ID"<10)


20 rows selected.

Elapsed: 00:00:00.03
22:48:30 SCOTT@zytrac1>variable v_id number; 
22:48:45 SCOTT@zytrac1>exec :v_id:=900; 

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
22:48:49 SCOTT@zytrac1>select sum(object_id) from t where id<:v_id;

SUM(OBJECT_ID)
--------------
        451307

Elapsed: 00:00:00.00
22:48:54 SCOTT@zytrac1>select * from table(dbms_xplan.display_cursor()); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  7qcp6urqh7d2j, child number 0
-------------------------------------
select sum(object_id) from t where id<:v_id

Plan hash value: 2966233522

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"<:V_ID)


19 rows selected.

Elapsed: 00:00:00.04
22:49:01 SCOTT@zytrac1>exec :v_id:=10; 

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
22:49:09 SCOTT@zytrac1>select sum(object_id) from t where id<:v_id;

SUM(OBJECT_ID)
--------------
           261

Elapsed: 00:00:00.00
22:49:13 SCOTT@zytrac1>select * from table(dbms_xplan.display_cursor()); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  7qcp6urqh7d2j, child number 0
-------------------------------------
select sum(object_id) from t where id<:v_id

Plan hash value: 2966233522

---------------------------------------------------------------------------
| Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE    |      |     1 |     8 |            |          |
|*  2 |   TABLE ACCESS FULL| T    |   900 |  7200 |     3   (0)| 00:00:01 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("ID"<:V_ID)


19 rows selected.

Elapsed: 00:00:00.04
22:49:19 SCOTT@zytrac1>alter system flush shared_pool;

System altered.

Elapsed: 00:00:00.24
22:49:36 SCOTT@zytrac1>print v_id; 

      V_ID
----------
        10

22:49:41 SCOTT@zytrac1>select round(avg(object_id)) from t where id<:v_id; 

ROUND(AVG(OBJECT_ID))
---------------------
                   29

Elapsed: 00:00:00.02
22:49:46 SCOTT@zytrac1>select * from table(dbms_xplan.display_cursor()); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0bx53mgt4qqnt, child number 0
-------------------------------------
select round(avg(object_id)) from t where id<:v_id

Plan hash value: 4270555908

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("ID"<:V_ID)


20 rows selected.

Elapsed: 00:00:00.55
22:49:54 SCOTT@zytrac1>exec :v_id:=900;  

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
22:50:09 SCOTT@zytrac1>select round(avg(object_id)) from t where id<:v_id; 

ROUND(AVG(OBJECT_ID))
---------------------
                  502

Elapsed: 00:00:00.00
22:50:14 SCOTT@zytrac1> select * from table(dbms_xplan.display_cursor()); 

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0bx53mgt4qqnt, child number 0
-------------------------------------
select round(avg(object_id)) from t where id<:v_id

Plan hash value: 4270555908

-------------------------------------------------------------------------------------
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |      |       |       |     3 (100)|          |
|   1 |  SORT AGGREGATE              |      |     1 |     8 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| T    |     9 |    72 |     3   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | T_PK |     9 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   3 - access("ID"<:V_ID)


20 rows selected.

Elapsed: 00:00:00.01
22:50:19 SCOTT@zytrac1>


select sql_id,child_number, is_bind_sensitive, is_bind_aware, is_shareable
  from v$sql
 where sql_id in ('0bx53mgt4qqnt')
 order by child_number; 
SQL_ID                     CHILD_NUMBER IS IS IS
-------------------------- ------------ -- -- --
7qcp6urqh7d2j                         0 N  N  Y

在Oracle 11g 以後在繫結變數這塊有所以改變,會生成一個範圍值的執行計劃。然後每次傳變數進去就對比範圍,選擇最優的執行計劃。與這個功能相關的引數儲存在v$sql檢視中:is_bind_sensitive,is_bind_aware,is_shareable。這幾個欄位,在Oracle 10g的v$sql 視圖裡是沒有的。
IS_BIND_SENSITIVE:指示遊標是否為對繫結敏感,值為YES | NO。符合以下情況的查詢稱為對繫結敏感的查詢:計算謂詞選擇性時優化程式為其掃視繫結變數值,並且繫結變數值的更改可能導致不同計劃。
IS_BIND_AWARE:指示遊標是否為能標識繫結的遊標,值為YES | NO。遊標快取記憶體中已標記為使用能識別繫結的遊標共享的遊標稱為能標識繫結的遊標。

參考連結:
https://blog.csdn.net/luis_ora/article/details/82109986
https://blog.csdn.net/leshami/article/details/6923627
https://www.cnblogs.com/xibuhaohao/p/11325211.html
https://www.cnblogs.com/Richardzhu/archive/2013/01/21/2869837.html