【DB筆試面試586】在Oracle中,什麼是自適應游標共享(3)?
- 2019 年 10 月 10 日
- 筆記
現在將的值修改為「JAVA CLASS」,然後再次執行目標SQL:
LHR@orclasm > EXEC :X :='CLUSTER'; PL/SQL procedure successfully completed. LHR@orclasm > SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X; COUNT(*) ---------- 2 LHR@orclasm > LHR@orclasm > SELECT A.SQL_TEXT, A.SQL_ID,A.VERSION_COUNT,A.EXECUTIONS FROM V$SQLAREA A WHERE A.SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ---------------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X bt8tk3f1tnwcf 6 7 LHR@orclasm > SELECT A.SQL_ID,A.CHILD_NUMBER,A.EXECUTIONS,A.BUFFER_GETS,A.IS_BIND_SENSITIVE,A.IS_BIND_AWARE,A.IS_SHAREABLE,A.PLAN_HASH_VALUE FROM V$SQL A WHERE A.SQL_ID='bt8tk3f1tnwcf'; SQL_ID CHILD_NUMBER EXECUTIONS BUFFER_GETS I I I PLAN_HASH_VALUE ------------- ------------ ---------- ----------- - - - --------------- bt8tk3f1tnwcf 0 2 309 Y N N 3002671579 bt8tk3f1tnwcf 1 1 522 Y Y Y 4256744017 bt8tk3f1tnwcf 2 1 16 Y Y N 3002671579 bt8tk3f1tnwcf 3 1 79 Y Y N 3002671579 bt8tk3f1tnwcf 4 1 74 Y Y N 3002671579 bt8tk3f1tnwcf 5 1 3 Y Y Y 3002671579
從如下查詢結果可以看到目標SQL對應的列VERSION_COUNT的值從之前的5變為了現在的6,列EXECUTIONS的值為7,說明Oracle在第7次執行目標SQL時依然用的是硬解析。從查詢結果可以看到,Oracle此時新生成了一個CHILD_NUMBER為5的Child Cursor,並且把存儲相同執行計劃的CHILD_NUMBER為4的原有Child Cursor標記為非共享。
目標SQL現在的執行計劃為如下所示:
LHR@orclasm > SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bt8tk3f1tnwcf',5,'advanced')); PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------- SQL_ID bt8tk3f1tnwcf, child number 5 ------------------------------------- SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X Plan hash value: 3002671579 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 7 | | | |* 2 | INDEX RANGE SCAN| IDX_ACS_OBJID_LHR | 2 | 14 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.3') DB_VERSION('11.2.0.3') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX(@"SEL$1" "T"@"SEL$1" ("T_ACS_20170611_LHR"."OBJECT_TYPE")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - :X (VARCHAR2(30), CSID=852): 'CLUSTER' Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("T"."OBJECT_TYPE"=:X) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22]
從上述顯示內容可以看出,目標SQL現在的執行計划走的還是對索引的索引範圍掃描,確實與CHILD_NUMBER為4的原有Child Cursor中存儲的執行計劃相同。注意,「Peeked Binds」部分的內容為「1 – :X (VARCHAR2(30), CSID=852): 'CLUSTER'」,說明Oracle在硬解析上述SQL的過程中確實再次使用了綁定變量窺探,並且做「窺探」這個動作時看到的綁定變量的輸入值為「CLUSTER」。
對於上述CHILD_NUMBER為5的Child Cursor,綁定變量X的輸入值為「CLUSTER」時對應的記錄數為2,表TI的記錄數為78174,帶入合併後的計算公式:
LHR@orclasm > SELECT ROUND(0.9*(2/78174),6) low,ROUND(1.1*(2/78174),6) HIGH FROM DUAL; LOW HIGH ---------- ---------- 0.000023 0.000028 LHR@orclasm > SELECT * FROM V$SQL_CS_SELECTIVITY D WHERE D.SQL_ID='bt8tk3f1tnwcf' ORDER BY CHILD_NUMBER; ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER PREDICATE RANGE_ID LOW HIGH ---------------- ---------- ------------- ------------ ---------------------------------------- ---------- ---------- ---------- 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 1 =X 0 0.711697 0.869852 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 2 =X 0 0.035482 0.043367 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 3 =X 0 0.035482 0.052317 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 4 =X 0 0.027412 0.052317 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 5 =X 0 0.000023 0.052317 LHR@orclasm > SELECT * FROM V$SQL_CS_STATISTICS D WHERE D.SQL_ID='bt8tk3f1tnwcf' ORDER BY D.CHILD_NUMBER; ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER BIND_SET_HASH_VALUE P EXECUTIONS ROWS_PROCESSED BUFFER_GETS CPU_TIME ---------------- ---------- ------------- ------------ ------------------- - ---------- -------------- ----------- ---------- 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 0 821942781 Y 1 3 54 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 1 3197905255 Y 1 61819 522 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 2 3279106319 Y 1 3083 16 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 3 3683986157 Y 1 3719 79 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 4 4071504174 Y 1 2382 74 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 5 821942781 Y 1 3 3 0
從上述計算結果可以看出,現在CHILD_NUMBER為5的Child Cursor對應的可選擇率範圍為[0.00002,0.000028],根本就不在之前V$SQL_CS_SELECTIVITY中記錄的之內,所以Oracle此時還是得用硬解析。和之前一樣,Oracle現在也得做Cursor合併。只不過這次是擴展新Child Cursor對應的可選擇率範圍的上限。CHILD_NUMBER為4的原有Child Cursor對應的可選擇率範圍為[0.027412,0.052317],CHILD_NUMBER為5的新Child Cursor對應的可選擇率範圍為[0.000023,0.000028],而0.052317是大於0.000028的,所以這裡Oracle對新Child Cursor的可選擇率範圍的上限做了擴展,擴展後該Child Cursor對應的可選擇率範圍就變成[0.000023,0.052317]。
上述SQL總共執行了7次,但有6次都是硬解析。究其根本原因,還是因為在自適應共享游標被啟用的前提條件下,當已經被標記為Bind Aware的Child Cursor所對應的目標SQL再次被執行時,Oracle會根據當前傳入的綁定變量值所對應的謂詞條件的可選擇率,來決定該SQL此時的執行是用硬解析還是用軟解析/軟軟解析。如果當前傳入的綁定變量值所在的謂詞條件的可選擇率處於該SQL之前硬解析時同名謂詞條件在V$SQL_CS_STATISTICS中記錄的可選擇率範圍之內,則此時Oracle就會使用軟解析/軟軟解析,反之則是硬解析。上述SQL從第4次到第7次的連續4次執行時,對應的謂詞條件的可選擇率範圍均不在之前V$SQL_CS_SELECTIVITY中記錄的相關舊Child Cursor對應的可選擇率範圍之內,所以這4次執行時Oracle都被迫使用硬解析。
在現在這種狀況下,如何才能讓目標SQL再次執行時使用軟解析/軟軟解析呢?很簡單,只需要綁定變量X賦值後其對應謂詞條件的可選擇率的範圍落在V$SQL_CS_SELECTIVITY中記錄的區間[0.711697,0.869852]或[0.000023,0.052317]內就可以了。
現在將的值修改為「VIEW」,然後再次執行目標SQL:
LHR@orclasm > EXEC :X :='VIEW'; PL/SQL procedure successfully completed. LHR@orclasm > SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X; COUNT(*) ---------- 1231 LHR@orclasm > SELECT A.SQL_TEXT, A.SQL_ID,A.VERSION_COUNT,A.EXECUTIONS FROM V$SQLAREA A WHERE A.SQL_TEXT LIKE 'SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=%'; SQL_TEXT SQL_ID VERSION_COUNT EXECUTIONS ---------------------------------------------------------------------------------------- ------------- ------------- ---------- SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X bt8tk3f1tnwcf 6 8 LHR@orclasm > SELECT A.SQL_ID,A.CHILD_NUMBER,A.EXECUTIONS,A.BUFFER_GETS,A.IS_BIND_SENSITIVE,A.IS_BIND_AWARE,A.IS_SHAREABLE,A.PLAN_HASH_VALUE FROM V$SQL A WHERE A.SQL_ID='bt8tk3f1tnwcf'; SQL_ID CHILD_NUMBER EXECUTIONS BUFFER_GETS I I I PLAN_HASH_VALUE ------------- ------------ ---------- ----------- - - - --------------- bt8tk3f1tnwcf 0 2 309 Y N N 3002671579 bt8tk3f1tnwcf 1 1 522 Y Y Y 4256744017 bt8tk3f1tnwcf 2 1 16 Y Y N 3002671579 bt8tk3f1tnwcf 3 1 79 Y Y N 3002671579 bt8tk3f1tnwcf 4 1 74 Y Y N 3002671579 bt8tk3f1tnwcf 5 2 18 Y Y Y 3002671579
從如下查詢結果可以看到目標SQL對應的列VERSION_COUNT的值還是保持之前的6不變,列EXECUTIONS的值從之前的7變為現在的8,說明Oracle在第8次執行目標SQL時確實用的是軟解析/軟軟解析。CHILD_NUMBER為5的Child Cursor中的EXECUTIONS列的值從1變為了2,說明目標SQL確實重用的是CHILD_NUMBER為5的Child Cursor中的解析樹和執行計劃。
目標SQL現在的執行計劃為如下所示:
LHR@orclasm > SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('bt8tk3f1tnwcf',5,'advanced')); PLAN_TABLE_OUTPUT ----------------------------------------------------------------------------- SQL_ID bt8tk3f1tnwcf, child number 5 ------------------------------------- SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYPE=:X Plan hash value: 3002671579 --------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 3 (100)| | | 1 | SORT AGGREGATE | | 1 | 7 | | | |* 2 | INDEX RANGE SCAN| IDX_ACS_OBJID_LHR | 2 | 14 | 3 (0)| 00:00:01 | --------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / T@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.3') DB_VERSION('11.2.0.3') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX(@"SEL$1" "T"@"SEL$1" ("T_ACS_20170611_LHR"."OBJECT_TYPE")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - :X (VARCHAR2(30), CSID=852): 'CLUSTER' Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("T"."OBJECT_TYPE"=:X) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT(*)[22]
從上述顯示內容可以看出,目標SQL現在的執行計划走的還是對索引的索引範圍掃描,確實與CHILD_NUMBER為4的原有Child Cursor中存儲的執行計劃相同。注意,「Peeked Binds」部分的內容為「1 – :X (VARCHAR2(30), CSID=852): 'CLUSTER'」,說明Oracle確實沿用了之前做「窺探」操作時綁定變量X的輸入值為「CLUSTER」所對應的執行計劃。
對於上述CHILD_NUMBER為5的Child Cursor,綁定變量X的輸入值為「VIEW」時對應的記錄數為1231,表TI的記錄數為78174,帶入合併後的計算公式:
LHR@orclasm > SELECT ROUND(0.9*(1231/78174),6) low,ROUND(1.1*(1231/78174),6) HIGH FROM DUAL; LOW HIGH ---------- ---------- 0.014172 0.017322 LHR@orclasm > SELECT * FROM V$SQL_CS_SELECTIVITY D WHERE D.SQL_ID='bt8tk3f1tnwcf' ORDER BY CHILD_NUMBER; ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER PREDICATE RANGE_ID LOW HIGH ---------------- ---------- ------------- ------------ ---------------------------------------- ---------- ---------- ---------- 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 1 =X 0 0.711697 0.869852 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 2 =X 0 0.035482 0.043367 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 3 =X 0 0.035482 0.052317 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 4 =X 0 0.027412 0.052317 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 5 =X 0 0.000023 0.052317 LHR@orclasm > SELECT * FROM V$SQL_CS_STATISTICS D WHERE D.SQL_ID='bt8tk3f1tnwcf' ORDER BY D.CHILD_NUMBER; ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER BIND_SET_HASH_VALUE P EXECUTIONS ROWS_PROCESSED BUFFER_GETS CPU_TIME ---------------- ---------- ------------- ------------ ------------------- - ---------- -------------- ----------- ---------- 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 0 821942781 Y 1 3 54 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 1 3197905255 Y 1 61819 522 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 2 3279106319 Y 1 3083 16 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 3 3683986157 Y 1 3719 79 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 4 4071504174 Y 1 2382 74 0 00000000AA2108A8 2207936910 bt8tk3f1tnwcf 5 821942781 Y 1 3 3 0 LHR@orclasm > SELECT D.SID,D.SQL_ID,D.CURSOR_TYPE,D.SQL_TEXT FROM V$OPEN_CURSOR D WHERE D.SQL_ID='bt8tk3f1tnwcf'; SID SQL_ID CURSOR_TYPE SQL_TEXT ---------- ------------- ---------------------------------------------------------------- ---------------------------------------------------------------------------------------- 33 bt8tk3f1tnwcf DICTIONARY LOOKUP CURSOR CACHED SELECT COUNT(*) FROM T_ACS_20170611_LHR T WHERE T.OBJECT_TYP LHR@orclasm > SELECT D.SQL_ID,D.CHILD_NUMBER,D.BIND_EQUIV_FAILURE FROM v$sql_shared_cursor d WHERE d.SQL_ID='bt8tk3f1tnwcf'; SQL_ID CHILD_NUMBER B ------------- ------------ - bt8tk3f1tnwcf 0 N bt8tk3f1tnwcf 1 Y bt8tk3f1tnwcf 2 Y bt8tk3f1tnwcf 3 Y bt8tk3f1tnwcf 4 Y bt8tk3f1tnwcf 5 Y LHR@orclasm >