梆定變量的長度不一致也可能會造成硬解析

當第一次使用梆定變量爲字符串類型,並且小於32bytes時,oracle捕獲這個梆定變量,並改寫該梆定變量的字符串長度爲32Bytes。如果第二次再使用該sql和梆定變量,如果梆定變量長度超過32字節小於128字節,則oracle會自動將該梆定變量長度改爲128字節,並且重新生成一個子遊標和執行計劃,造成相同梆定變量的sql的執行計劃不能共享,需要重新生成解析樹和執行計劃(即是硬解析),過多的硬解析是萬惡之源,會佔用大量的CPU、IO和內存資源,造成系統性能瓶頸。所以使用相同SQL的相同梆定變量時,要特別注意每次該梆定變量的長度是否在符合軟解析的區間長度內。

 

測試結果如下:

1)、創建一個10個字節可變長度的字符串變量 v:

23:24:15SYS@orcl*SQL> var v varchar2(10);

23:24:26SYS@orcl*SQL> exec :v :='abcd';

23:24:26SYS@orcl*SQL> print v;

V

----------

abcd

 

 

2)、將變量 v 梆定到 sql 的查詢謂詞條件值中,並執行:

23:24:27SYS@orcl*SQL> select * from tuser.testbind where test=:v;

 

TEST

----------

abcd

 

 

3)、查詢上面執行的sql在 Library Cache (Sharedpool共享池中的庫緩存)中生成遊標和執行計劃的 sql_id,並注意子游標號CHILD_NUMBER是0(第一個子游標,即第一個執行計劃版本):

23:24:32SYS@orcl*SQL> select sql_id,sql_text,child_number from v$sql where sql_textlike 'select * from tuser.testbind where test=:v%';

 

SQL_ID                     SQL_TEXT                                                          CHILD_NUMBER

-------------------------------------------------------------------------------------- ------------------

13gr9g2810v9c              select * from tuser.testbindwhere test=:v                                   0

 

 

4)、由於是第一次執行第2步的sql,並且梆定變量長度還沒有變化,所以如下顯示的梆定變量長度已更改字段(BIND_LENGTH_UPGRADEABLE)爲No:

23:24:38SYS@orcl*SQL> select sql_id,child_number,BIND_LENGTH_UPGRADEABLE fromv$sql_shared_cursor

23:24:50   2 where sql_id='13gr9g2810v9c';

 

SQL_ID                           CHILD_NUMBERBIND_LENGTH_UPGRADEABLE

-------------------------------------------- ------------------------------

13gr9g2810v9c                               0 N

 

 

5)、查詢捕獲的梆定變量信息,DATATYPE_STRING字段列自動將小於32字節的梆定變量更改爲32字節:

23:25:03SYS@orcl*SQL> select position,LAST_CAPTURED,datatype_string,value_string

23:25:04   2 from v$sql_bind_capture

23:25:04   3 where sql_id='13gr9g2810v9c';

 

NAME          POSITION LAST_CAPTURED          DATATYPE_STRING     VALUE_STRING

-----------   -------- ----------------------------------------- -------------------------

:V            1        2017-04-14 23:24:31    VARCHAR2(32)        abcd

 

 

6)、再將梆定變量 v 的長度更改爲超過32字節,如下33字節:

23:25:05SYS@orcl*SQL>

23:25:09SYS@orcl*SQL> var v varchar2(33);

23:25:18SYS@orcl*SQL> exec :v :='abcd';

23:25:18SYS@orcl*SQL> print v;

V

----------

abcd

 

 

7)、再次執行以上第二步的sql:

23:25:19SYS@orcl*SQL> select * from tuser.testbind where test=:v;

 

TEST

----------

abcd

 

 

 

8)、和以上第3步對照,再次查詢 Library Cache 中的 v$sql字典視圖,發現生成多了一個子遊標(CHILD_NUMBER=1),也就是發生硬解析,重新生成了新的執行計劃:

23:25:23SYS@orcl*SQL> select sql_id,sql_text,child_number from v$sql where sql_textlike 'select * from tuser.testbind where test=:v%';

 

SQL_ID                     SQL_TEXT                                                          CHILD_NUMBER

-------------------------------------------------------------------------------------- ------------------

13gr9g2810v9c              select * from tuser.testbindwhere test=:v                                   0

13gr9g2810v9c              select * from tuser.testbindwhere test=:v                                   1

 

 

 

9)、和以上第4步對照,再次查詢可以發現,oracle已經捕獲到梆定變量 v 的長度相比之前發生了變化:

23:25:39SYS@orcl*SQL> select sql_id,child_number,BIND_LENGTH_UPGRADEABLE fromv$sql_shared_cursor

23:25:40   2 where sql_id='13gr9g2810v9c';

 

SQL_ID                           CHILD_NUMBERBIND_LENGTH_UPGRADEABLE

-------------------------------------------- ------------------------------

13gr9g2810v9c                               0 N

13gr9g2810v9c                               1 Y

 

 

 

10)、oracle 自動將梆定變量 v 的長度改爲128字節,第二次定義時是33字節(見第6步)

23:25:40SYS@orcl*SQL> select position,LAST_CAPTURED,datatype_string,value_string

23:25:46   2 from v$sql_bind_capture

23:25:46   3 where sql_id='13gr9g2810v9c';

 

          POSITION LAST_CAPTURED       DATATYPE_STRING                VALUE_STRING

------------------------------------- ------------------------------------------------------------

                 1 2017-04-14 23:25:23VARCHAR2(128)                  abcd

                 1 2017-04-14 23:24:31VARCHAR2(32)                   abcd

 

 

 

由此可見,雖然使用梆定變量能讓相同的SQL,不同的條件值可以走上相同的執行計劃,從而避免過多的硬解析,不會消耗過多的資源,但也要注意梆定變量長度的變化,否則使用了梆定變量也可能會產生硬解析,造成資源浪費。

(完)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章