自適應游標共享會使包含綁定變量的單個語句擁有多個執行計划,所謂自適應是指執行計划會依據綁定變量的具體值而適配一個最適合該值的執行計划。
隱藏參數_optimizer_adaptive_cursor_sharing=TRUE 開啟或關閉此特性。
首先:游標是否可以被ACS使用,首先游標必須是綁定變量敏感的游標,也就是說最優的執行計划會依賴於綁定變量具體的值。數據庫會監控綁定變量敏感的游標,觀察是否不同的執行計划會對不同的綁定變量值有好處。
游標在以下兩個條件滿足的時候會被標記為綁定變量敏感的游標:
1.優化器通過綁定變量窺測去做選擇性評估。
2.在綁定變量的列上存在直方圖信息。
等等
對於傳入的每個新的游標的具體值,數據庫會記錄語句執行時的統計信息,語句執行完后,數據庫會對比這次執行的統計信息與之前執行的統計信息,如果兩者差距很大,則數據庫會將該游標標記為 bind-aware 的游標。
當一個游標被標記為 bind-aware的游標后,只要綁定變量的值落入之前收集的綁定變量值與選擇率的直方圖內,優化器就會重用一個已經存在並且對該綁定變量來說最優的執行計划,如果綁定變量的值沒有落入上述直方圖內,則會進行硬解析,由此可見,自適應游標共享的好處是既減少了硬解析的次數,對於不同的綁定變量值來說又能找到一個合適它的執行計划。
游標合並:
當優化器創建新的執行計划為 bind-aware的游標后,如果該執行計划和一個已經存在的游標相同的時候,在這種情況下,優化器會合並游標去節省內存空間,數據庫會擴大選擇性范圍去包括新的綁定變量值的選擇性。
游標共享相關的性能視圖:
-
V$SQL
去檢查一個游標是否是 bind-sensitive 以及bind-aware的游標。 -
V$SQL_CS_HISTOGRAM 有綁定變量,選擇性,執行次數的直方圖。
-
V$SQL_CS_SELECTIVITY 包括綁定變量對選擇性范圍。
V$SQL_CS_STATISTICS
summarizes 包括優化器是否將某個游標標記為bind_aware 的統計信息。
SQL> var v_own varchar2(100); SQL> exec :v_own:='sys'; PL/SQL procedure successfully completed v_own --------- sys SQL>select count(object_name) from testtab where owner=:v_own; COUNT(OBJECT_NAME) ------------------ 0 v_own --------- sys SQL> select count(object_name) from testtab where owner=:v_own; COUNT(OBJECT_NAME) ------------------ 0
檢查執行計划
L_ID 85man3fnzwka5, child number 0 ------------------------------------- select count(object_name) from testtab where owner=:v_own Plan hash value: 1556530801 ----------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ----------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 2 (100)| | 1 |00:00:00.01 | 3 | | 1 | SORT AGGREGATE | | 1 | 1 | 83 | | | 1 |00:00:00.01 | 3 | | 2 | TABLE ACCESS BY INDEX ROWID| TESTTAB | 1 | 1 | 83 | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 3 | |* 3 | INDEX RANGE SCAN | IND_TEST | 1 | 1 | | 2 (0)| 00:00:01 | 0 |00:00:00.01 | 3 | ----------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / TESTTAB@SEL$1 3 - SEL$1 / TESTTAB@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_RS_ASC(@"SEL$1" "TESTTAB"@"SEL$1" ("TESTTAB"."OWNER")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - (VARCHAR2(30), CSID=178): 'sys' Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("OWNER"=:V_OWN) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT("OBJECT_NAME")[22] 2 - "OBJECT_NAME"[VARCHAR2,128] 3 - "TESTTAB".ROWID[ROWID,10] Note ----- - dynamic sampling used for this statement (level=2)
此時自適應游標共享還沒起作用
select IS_BIND_SENSITIVE,IS_BIND_AWARE,IS_SHAREABLE from v$sql where sql_id='85man3fnzwka5'
IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE
N N Y
列上收集直方圖信息
exec dbms_stats.gather_table_stats(ownname => 'WXC',tabname => 'TESTTAB',method_opt => 'for all indexed columns size auto');
SQL> exec :v_own:='SYS'; PL/SQL procedure successfully completed v_own --------- SYS SQL> select count(object_name) from testtab where owner=:v_own; COUNT(OBJECT_NAME) ------------------ 2021120 v_own --------- SYS
再次執行,由於SYS用戶占表中半數以上,所以執行計划應該選擇走全表掃描。
SQL_ID 85man3fnzwka5, child number 1 ------------------------------------- select count(object_name) from testtab where owner=:v_own Plan hash value: 269898743 ------------------------------------------------------------------------------------------------------------------------ | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ------------------------------------------------------------------------------------------------------------------------ | 0 | SELECT STATEMENT | | 1 | | | 18664 (100)| | 1 |00:00:00.46 | 68720 | | 1 | SORT AGGREGATE | | 1 | 1 | 72 | | | 1 |00:00:00.46 | 68720 | |* 2 | TABLE ACCESS FULL| TESTTAB | 1 | 2009K| 137M| 18664 (1)| 00:03:44 | 2021K|00:00:00.36 | 68720 | ------------------------------------------------------------------------------------------------------------------------ Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / TESTTAB@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") FULL(@"SEL$1" "TESTTAB"@"SEL$1") END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - (VARCHAR2(30), CSID=178): 'SYS' Predicate Information (identified by operation id): --------------------------------------------------- 2 - filter("OWNER"=:V_OWN) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT("OBJECT_NAME")[22] 2 - "OBJECT_NAME"[VARCHAR2,128]
自適應游標共享已經生效如下
select IS_BIND_SENSITIVE,IS_BIND_AWARE,IS_SHAREABLE from v$sql where sql_id='85man3fnzwka5'
SQL_TEXT IS_BIND_SENSITIVE IS_BIND_AWARE IS_SHAREABLE select count(object_name) from testtab where owner=:v_own N N Y select count(object_name) from testtab where owner=:v_own Y N N select count(object_name) from testtab where owner=:v_own Y Y Y
繼續測試,使綁定變量值為‘WXC’繼續執行,由於wxc只在表中有幾行數據,所以走索引掃描是合適的,執行計划如下
SQL_ID 85man3fnzwka5, child number 2 ------------------------------------- select count(object_name) from testtab where owner=:v_own Plan hash value: 1556530801 ----------------------------------------------------------------------------------------------------------------------------------- | Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers | ----------------------------------------------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | | 20 (100)| | 1 |00:00:00.01 | 67 | | 1 | SORT AGGREGATE | | 1 | 1 | 72 | | | 1 |00:00:00.01 | 67 | | 2 | TABLE ACCESS BY INDEX ROWID| TESTTAB | 1 | 446 | 32112 | 20 (0)| 00:00:01 | 64 |00:00:00.01 | 67 | |* 3 | INDEX RANGE SCAN | IND_TEST | 1 | 450 | | 4 (0)| 00:00:01 | 64 |00:00:00.01 | 3 | ----------------------------------------------------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 2 - SEL$1 / TESTTAB@SEL$1 3 - SEL$1 / TESTTAB@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_RS_ASC(@"SEL$1" "TESTTAB"@"SEL$1" ("TESTTAB"."OWNER")) END_OUTLINE_DATA */ Peeked Binds (identified by position): -------------------------------------- 1 - (VARCHAR2(30), CSID=178): 'WXC' Predicate Information (identified by operation id): --------------------------------------------------- 3 - access("OWNER"=:V_OWN) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - (#keys=0) COUNT("OBJECT_NAME")[22] 2 - "OBJECT_NAME"[VARCHAR2,128] 3 - "TESTTAB".ROWID[ROWID,10]
可見自適應游標共享確實能根據綁定變量的具體值選擇合適的執行計划。
檢查如下三個視圖,相關信息如下。
SELECT * FROM v$sql_cs_histogram where sql_id='85man3fnzwka5'
ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER BUCKET_ID COUNT 00000000A84CDFE0 2852014405 85man3fnzwka5 2 0 6 00000000A84CDFE0 2852014405 85man3fnzwka5 2 1 0 00000000A84CDFE0 2852014405 85man3fnzwka5 2 2 0 00000000A84CDFE0 2852014405 85man3fnzwka5 1 0 2 00000000A84CDFE0 2852014405 85man3fnzwka5 1 1 0 00000000A84CDFE0 2852014405 85man3fnzwka5 1 2 6
SELECT * from v$sql_cs_selectivity where sql_id='85man3fnzwka5'
ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER PREDICATE RANGE_ID LOW HIGH 00000000A84CDFE0 85man3fnzwka5 2 =V_OWN 0 0.000083 0.000102
SELECT * from v$sql_cs_statistics where sql_id = '85man3fnzwka5'
ADDRESS HASH_VALUE SQL_ID CHILD_NUMBER BIND_SET_HASH_VALUE PEEKED EXECUTIONS ROWS_PROCESSED BUFFER_GETS CPU_TIME 1 00000000A84CDFE0 2852014405 85man3fnzwka5 2 1699580835 Y 1 258 67 0 2 00000000A84CDFE0 2852014405 85man3fnzwka5 1 3596483694 Y 1 4042242 68720 0
綁定變量捕獲信息如下
SELECT * from v$sql_bind_capture where sql_id = '85man3fnzwka5'
ADDRESS HASH_VALUE SQL_ID CHILD_ADDRESS CHILD_NUMBER NAME POSITION DUP_POSITION DATATYPE DATATYPE_STRING CHARACTER_SID PRECISION SCALE MAX_LENGTH WAS_CAPTURED LAST_CAPTURED VALUE_STRING 1 00000000A84CDFE0 2852014405 85man3fnzwka5 000000009DA0D950 2 :V_OWN 1 1 VARCHAR2(4000) 178 4000 YES 2016/10/9 7:14:02 WXC 2 00000000A84CDFE0 2852014405 85man3fnzwka5 000000009DA120B8 1 :V_OWN 1 1 VARCHAR2(4000) 178 4000 YES 2016/10/9 7:06:52 SYS 3 00000000A84CDFE0 2852014405 85man3fnzwka5 00000000A84CDB80 0 :V_OWN 1 1 VARCHAR2(4000) 178 4000 YES 2016/10/9 6:55:05 SYS