oracle 11g 變數窺視和acs最佳實踐

531968912發表於2016-12-21
select t.column_name,                                                           
       t.num_distinct,                                                          
       t.num_buckets,                                                           
       t.last_analyzed,                                                         
       t.HISTOGRAM                                                              
  from dba_tab_col_statistics t                                                 
 where table_name = 'TI_O_YWTOCREDIT'                                           
 
  關於histogram總共有兩種,一種是HEIGHT BALANCED,另外一種是FREQUENCY,這個是oracle是根據NDV來進行選擇 
  如果有254個以下的非空的不同值,就是FREQUENCY的柱狀圖                                                  
  如果有254個以上的非空的不同值,就是HEIGHT BALANCED的柱狀圖                                            
                                                                                                                          
 HEIGHT BALANCED 高度平衡直方圖(a.ENDPOINT_NUMBER(代表桶號),a.ENDPOINT_VALUE )
 FREQUENCY    頻率直方圖(a.ENDPOINT_NUMBER(代表桶號),a.ENDPOINT_VALUE )       
 
 
 
 今天談談下面這幾個引數對資料庫效能和穩定性的影響:


cursor_sharing:遊標共享


_optim_peek_user_binds:繫結變數窺視


_optimizer_adaptive_cursor_sharing:自適應遊標共享(簡稱ACS),一般還包括另外兩個_optimizer_extended_cursor_sharing和_optimizer_extended_cursor_sharing_rel 引數)









_optim_peek_user_binds和ACS:


在10g,因為沒有ACS,一般建議客戶關閉繫結變數窺視功能的情況多一些。


在11g,很多客戶還是將繫結變數窺視和ACS都關閉了,原因有的是資料庫從1g升級而來,升級後沒有改,還有就是因為ACS早期版本有一些bug。
其實這是兩個很好的引數,可以在程式碼寫的不是太好的情況下,也能獲得比較好的效能。雖然ACS可能還有一些小bug沒有解決(有的bug是在很特殊的情況下才會觸發),
到了11204版本應該都不是大問題了。老虎劉建議還是都開啟比較好。









最重要的引數還在下面,如果做到了下面這兩點,上面兩個引數就顯得不是那麼重要了:







首先,cursor_sharing這個引數對系統效能和穩定性都非常重要,可惜經常被忽略,建議使用該引數的預設值:


    即 cursor_sharing=EXACT  (而不是FORCE或similar)


   這要求應該使用繫結變數的地方,必須使用繫結變數。這個對於OLTP系統來說是鐵律,不容置疑,
   cursor_sharing=FORCE通常就是為了解決該使用繫結變數而沒有使用繫結變數的情況。
   前年在網上看到一個廣為流傳的某水果公司的AWR報告,居然設定 cursor_sharing= FORCE ,令人感嘆啊。







其次,還有一個重要的補充條件:


不該使用繫結變數的地方,不用繫結變數:對那些唯一值較少的欄位,特別是資料分佈不均的情況,
不建議使用繫結變數。如type、status等欄位,我們建議使用常量:where type=1 and status=2。


這種情況如果使用了繫結變數,就是繫結變數窺視和ACS發揮作用的時候。














如果cursor_sharing=FORCE;或者cursor_sharing=EXACT,但是在資料分佈不均的欄位上也使用了繫結變數(兩者基本上是等同的,雖然後一種略好於前一種情況),
那麼就要考慮“繫結變數窺視”和“自適應遊標”兩個引數的影響了。









看下面幾種情況:


1、關閉“繫結變數窺視”(預設是開啟):


ACS同時失效,這時系統的穩定性好(不會因為繫結變數的不同,發生執行計劃改變),
但是整體效能會下降:因為不能窺視繫結變數,只能按照欄位是資料分佈均勻的情況來計算,
在能否使用索引,返回行源的估值上,都會出現較大的偏差,有時可能會配合使用hint來提高SQL效能。









2、如果開啟了“繫結變數窺視”而不開啟ACS(預設是開啟):


那麼系統就會極不穩定:比如硬解析窺視到一個繫結變數適合全表掃描的執行計劃,不管接下來的繫結變數是否能使用索引,
都會一直全表掃描下去,直到下次硬解析時再次窺視繫結變數才可能重新生成新的執行計劃。









3、如果開啟“繫結變數窺視”,同時開啟ACS:


這種情況在解決了一部分穩定性的同時,兼顧了效能。也是11g新增的ACS比10g沒有ACS進步的地方:
執行計劃不再從一而終,而是會根據繫結變數的不同,不是很及時的做出調整:
比如第一次窺視到的繫結變數適合全表掃描,那麼第二次即使使用的繫結變數適合走索引,也還是會使用全表掃描的執行計劃,
下一次再次執行就會糾正為使用索引的執行計劃(具體請參考ACS的實現原理)。









繫結變數窺視和ACS這兩個引數是與直方圖資訊緊密聯絡在一起的,關閉直方圖收集,也就相當於關閉了繫結變數窺視和ACS,即使開啟了這兩個引數。













直方圖能較為準確的反映資料分佈不均欄位的資料分佈情況,一般使用預設選項(auto),
某些特殊情況可以補充或去掉某些欄位的直方圖資訊。一些客戶在資料庫級關閉收集直方圖的做法是不建議的。














總結:


最佳實踐:


cursor_sharing=EXACT + 合理使用繫結變數(合理就是:類似ID、account_no等唯一值等於或接近錶行數的欄位,必須使用繫結變數;
而type、status等唯一值少且數分別不均的欄位,不使用繫結變數)。


繫結變數窺視和ACS保持預設開啟狀態。














特殊情況:


1、欄位唯一值有一定的數量(介於少與多之間),比如1000個,如果資料分佈均勻,則可以使用繫結變數。
  如果欄位分佈不均,則把佔比多的幾個值,使用常量,其他值使用繫結變數。


2、欄位唯一值少,還有經常互相轉變的情況,比如常見的工單處理表:沒有處理的狀態是0,處理後的狀態是1,
  夜間統計資訊收集後,由於欄位值的不穩定,統計資訊經常不能反映表的實時資料分佈情況,這種情況談是否使用繫結變數已沒有意義,
  涉及這類表的SQL,可以關閉欄位上的直方圖收集,再配合rownum和hint 來提高SQL效率和穩定性,
  必要時還可以使用dynamic_sampling(動態取樣)來輔助最佳化器做出正確的執行計劃。












最差組合:


cursor_sharing=FORCE


_optim_peek_user_binds=TRUE(開啟繫結變數窺視)


_optimizer_adaptive_cursor_sharing=FALSE(關閉ACS,還有其他兩個引數也要一起設定)


執行計劃不穩定的同時還會帶來低效能。






使用ACS的前提條件:


1.繫結變數使用變數窺視;


2.繫結變數的列上使用直方圖;










關閉acs步驟:










我們先來看看跟ACS相關的三個隱藏引數,是用來控制是否啟用ACS


col ksppinm for a30


col ksppstvl for a20


col ksppdesc for a35


SELECT   ksppinm, ksppstvl, ksppdesc


FROM   x$ksppi x, x$ksppcv y


WHERE   x.indx = y.indx AND  ksppinm = '_optimizer_adaptive_cursor_sharing';


KSPPINM                        KSPPSTVL             KSPPDESC


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


_optimizer_adaptive_cursor_sha TRUE                 optimizer adaptive cursor sharing


ring










SELECT   ksppinm, ksppstvl, ksppdesc


FROM   x$ksppi x, x$ksppcv y


WHERE   x.indx = y.indx AND  ksppinm = '_optimizer_extended_cursor_sharing';


KSPPINM                        KSPPSTVL             KSPPDESC


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


_optimizer_extended_cursor_sha UDO                  optimizer extended cursor sharing


ring










SELECT   ksppinm, ksppstvl, ksppdesc


FROM   x$ksppi x, x$ksppcv y


WHERE   x.indx = y.indx AND  ksppinm = '_optimizer_extended_cursor_sharing_rel';


KSPPINM                        KSPPSTVL             KSPPDESC


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


_optimizer_extended_cursor_sha SIMPLE               optimizer extended cursor sharing f


ring_rel


所以如果我們要關閉ACS,使用如下的命令


alter system set "_optimizer_extended_cursor_sharing_rel"=none;


alter system set "_optimizer_extended_cursor_sharing"=none;


alter system set "_optimizer_adaptive_cursor_sharing"=false;


 
 
 
 
 
 
 
 
關於直方圖案例:
 
 下面我們就來進行實驗
準備一張測試表,資料分佈極不均勻
20:10:16 scott@prod> select count(*) from test where object_id=1;


     COUNT(*)
-------------
      2400000


Elapsed: 00:00:00.60
20:11:41 scott@prod> select count(*) from test;


     COUNT(*)
-------------
      2406496


20:07:06 scott@prod> create index idx_test on test(object_id);


Index created.


收集柱狀圖
exec dbms_stats.gather_table_stats('SCOTT','TEST',method_opt=>'for all columns size skewonly');


20:14:41 scott@prod> select COLUMN_NAME,HISTOGRAM from user_tab_columns where TABLE_NAME='TEST' and column_name='OBJECT_ID';


COLUMN_NAME                    HISTOGRAM
------------------------------ ---------------
OBJECT_ID                      HEIGHT BALANCED


關於histogram總共有兩種,一種是HEIGHT BALANCED,另外一種是FREQUENCY,這個是oracle是根據NDV來進行選擇
如果有254個以下的非空的不同值,就是FREQUENCY的柱狀圖
如果有254個以上的非空的不同值,就是HEIGHT BALANCED的柱狀圖
關於柱狀圖的其他的特性,我會在另外的文章中再進行總結
由於set autotrace on 不是顯示的實際的執行計劃,是根據統計資訊進行估算的,並不一定能夠反應真是的執行計劃,我們使用
select * from table(dbms_xplan.display_cursor('sql_id',null,'advanced'));來顯示正確的執行計劃


20:26:37 scott@prod> var x number
20:26:51 scott@prod> exec :x:=48056


PL/SQL procedure successfully completed.


20:27:03 scott@prod> select * from test where object_id=:x;


20:35:50 sys@prod> select sql_id,sql_text,EXECUTIONS  from v$sql where sql_text ='select * from test where object_id=:x';


SQL_ID        SQL_TEXT                                    EXECUTIONS
------------- ---------------------------------------- -------------
fk1y97mvmdu8f select * from test where object_id=:x                1


20:33:22 sys@prod> select * from table(dbms_xplan.display_cursor('fk1y97mvmdu8f',null,'advanced'));


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
SQL_ID  fk1y97mvmdu8f, child number 0
-------------------------------------
select * from test where object_id=:x


Plan hash value: 2473784974


----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |       |       |     4 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |     3 |   285 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |     3 |       |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------


Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------


   1 - SEL$1 / TEST@SEL$1
   2 - SEL$1 / TEST@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" "TEST"@"SEL$1" ("TEST"."OBJECT_ID"))
      END_OUTLINE_DATA
  */


Peeked Binds (identified by position):
--------------------------------------


   1 - :X (NUMBER): 48056


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


   2 - access("OBJECT_ID"=:X)


Column Projection Information (identified by operation id):
-----------------------------------------------------------


   1 - "TEST"."OWNER"[VARCHAR2,30], "TEST"."OBJECT_NAME"[VARCHAR2,128],
       "TEST"."SUBOBJECT_NAME"[VARCHAR2,30], "OBJECT_ID"[NUMBER,22],
       "TEST"."DATA_OBJECT_ID"[NUMBER,22], "TEST"."OBJECT_TYPE"[VARCHAR2,19],
       "TEST"."CREATED"[DATE,7], "TEST"."LAST_DDL_TIME"[DATE,7],
       "TEST"."TIMESTAMP"[VARCHAR2,19], "TEST"."STATUS"[VARCHAR2,7],
       "TEST"."TEMPORARY"[VARCHAR2,1], "TEST"."GENERATED"[VARCHAR2,1],
       "TEST"."SECONDARY"[VARCHAR2,1], "TEST"."NAMESPACE"[NUMBER,22],
       "TEST"."EDITION_NAME"[VARCHAR2,30]
   2 - "TEST".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22]


可以看到此時走的是索引的範圍掃描


我們換object_id=1的,可以看到,總共240多萬的表,object_id=1的就有240萬,按道理這種肯定是應該走全表掃描的
exec :x:=1
select * from test where object_id=:x;


20:36:23 sys@prod>  select sql_id,sql_text,EXECUTIONS  from v$sql where sql_text ='select * from test where object_id=:x';


SQL_ID        SQL_TEXT                                    EXECUTIONS
------------- ---------------------------------------- -------------
fk1y97mvmdu8f select * from test where object_id=:x                2


可以看到這個子游標的執行次數已經變成了2次
在來看此時的執行計劃
20:38:39 sys@prod> select * from table(dbms_xplan.display_cursor('fk1y97mvmdu8f',null,'advanced'));


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
SQL_ID  fk1y97mvmdu8f, child number 0
-------------------------------------
select * from test where object_id=:x


Plan hash value: 2473784974


----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |       |       |     4 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| TEST     |     3 |   285 |     4   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_TEST |     3 |       |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------------------


Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------


   1 - SEL$1 / TEST@SEL$1
   2 - SEL$1 / TEST@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" "TEST"@"SEL$1" ("TEST"."OBJECT_ID"))
      END_OUTLINE_DATA
  */


Peeked Binds (identified by position):
--------------------------------------


   1 - :X (NUMBER): 48056


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


   2 - access("OBJECT_ID"=:X)


Column Projection Information (identified by operation id):
-----------------------------------------------------------


   1 - "TEST"."OWNER"[VARCHAR2,30], "TEST"."OBJECT_NAME"[VARCHAR2,128],
       "TEST"."SUBOBJECT_NAME"[VARCHAR2,30], "OBJECT_ID"[NUMBER,22],
       "TEST"."DATA_OBJECT_ID"[NUMBER,22], "TEST"."OBJECT_TYPE"[VARCHAR2,19],
       "TEST"."CREATED"[DATE,7], "TEST"."LAST_DDL_TIME"[DATE,7],
       "TEST"."TIMESTAMP"[VARCHAR2,19], "TEST"."STATUS"[VARCHAR2,7],
       "TEST"."TEMPORARY"[VARCHAR2,1], "TEST"."GENERATED"[VARCHAR2,1],
       "TEST"."SECONDARY"[VARCHAR2,1], "TEST"."NAMESPACE"[NUMBER,22],
       "TEST"."EDITION_NAME"[VARCHAR2,30]
   2 - "TEST".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22]
還是索引的範圍的掃描,現在現在走這個執行計劃是不合適的,由於繫結變數窺視,oracle走錯了執行計劃
select CHILD_NUMBER,PLAN_HASH_VALUE,EXECUTIONS,
     BUFFER_GETS/EXECUTIONS BG_PER_EX,
     IS_BIND_SENSITIVE BS,IS_BIND_AWARE BA,IS_SHAREABLE S
     from v$sql where sql_id='fk1y97mvmdu8f'; 




select CHILD_NUMBER,PLAN_HASH_VALUE,EXECUTIONS,
BUFFER_GETS/EXECUTIONS BG_PER_EX,
IS_BIND_SENSITIVE BS,IS_BIND_AWARE BA,IS_SHAREABLE S
from v$sql where sql_id='fk1y97mvmdu8f'; 


 CHILD_NUMBER PLAN_HASH_VALUE    EXECUTIONS     BG_PER_EX B B S
------------- --------------- ------------- ------------- - - -
            0      2473784974             2          3913 Y N Y
            
從v$SQL中,可以看到這個cursor的資料,其中
IS_BIND_SENSITIVE=Y,表明使用繫結變數窺視來生成這次執行計劃,這次執行計劃是取決於這個繫結變數的,如果Oracle發現有其他的繫結變數出現,是可能生成其他的執行計劃的。
IS_BIND_AWARE=N,表明Oracle還沒有使用extended cursor sharing。
IS_SHAREABLE=Y,表明這個cursor可以被再次使用,即能夠共享;反之,設為N代表著這個cursor已經過時了,不會被再用了,這個cursor將會等待被age out出shared pool。


此時我們在執行這條sql語句
select sql_id,sql_text,child_number,executions,is_bind_sensitive,is_bind_aware,is_shareable,plan_hash_value from v$sql where sql_text ='select * from test where object_id=:x';


SQL_ID        SQL_TEXT                                  CHILD_NUMBER    EXECUTIONS I I I PLAN_HASH_VALUE
------------- ---------------------------------------- ------------- ------------- - - - ---------------
fk1y97mvmdu8f select * from test where object_id=:x                0             2 Y N N      2473784974
fk1y97mvmdu8f select * from test where object_id=:x                1             1 Y Y Y      1357081020
可以看到重新生成了新的子游標
檢視新遊標的執行計劃
Elapsed: 00:00:00.13
06:14:18 sys@orcl> select * from table(dbms_xplan.display_cursor('fk1y97mvmdu8f',1,'advanced'));


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------------------
SQL_ID  fk1y97mvmdu8f, child number 1
-------------------------------------
select * from test where object_id=:x


Plan hash value: 1357081020


--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |       |       |  5528 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST |  1369K|   125M|  5528   (1)| 00:01:07 |
--------------------------------------------------------------------------


Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------


   1 - SEL$1 / TEST@SEL$1


Outline Data
-------------


  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('11.2.0.4')
      DB_VERSION('11.2.0.4')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "TEST"@"SEL$1")
      END_OUTLINE_DATA
  */


Peeked Binds (identified by position):
--------------------------------------


   1 - :X (NUMBER): 100


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


   1 - filter("OBJECT_ID"=:X)


Column Projection Information (identified by operation id):
-----------------------------------------------------------


   1 - "TEST"."OWNER"[VARCHAR2,30], "TEST"."OBJECT_NAME"[VARCHAR2,128],
       "TEST"."SUBOBJECT_NAME"[VARCHAR2,30], "OBJECT_ID"[NUMBER,22],
       "TEST"."DATA_OBJECT_ID"[NUMBER,22], "TEST"."OBJECT_TYPE"[VARCHAR2,19],
       "TEST"."CREATED"[DATE,7], "TEST"."LAST_DDL_TIME"[DATE,7],
       "TEST"."TIMESTAMP"[VARCHAR2,19], "TEST"."STATUS"[VARCHAR2,7],
       "TEST"."TEMPORARY"[VARCHAR2,1], "TEST"."GENERATED"[VARCHAR2,1],
       "TEST"."SECONDARY"[VARCHAR2,1], "TEST"."NAMESPACE"[NUMBER,22],
       "TEST"."EDITION_NAME"[VARCHAR2,30]
       
如果此時我們賦予一個另外的值,我們再重新執行以下這個sql語句
06:18:00 kiwi@orcl> exec :x:=57603


PL/SQL procedure successfully completed.


Elapsed: 00:00:00.01
06:19:14 kiwi@orcl> select * from test where object_id=:x;




SQL_ID        SQL_TEXT                                  CHILD_NUMBER    EXECUTIONS I I I PLAN_HASH_VALUE
------------- ---------------------------------------- ------------- ------------- - - - ---------------
fk1y97mvmdu8f select * from test where object_id=:x                0             2 Y N N      2473784974
fk1y97mvmdu8f select * from test where object_id=:x                1             4 Y N N      1357081020
fk1y97mvmdu8f select * from test where object_id=:x                2             1 Y Y Y      2473784974


我們此時如果在反覆的執行
06:26:39 kiwi@orcl> exec :x:=100


PL/SQL procedure successfully completed.


Elapsed: 00:00:00.00
06:27:05 kiwi@orcl> select * from test where object_id=:x;


SQL_ID        SQL_TEXT                                  CHILD_NUMBER    EXECUTIONS I I I PLAN_HASH_VALUE
------------- ---------------------------------------- ------------- ------------- - - - ---------------
fk1y97mvmdu8f select * from test where object_id=:x                0             2 Y N N      2473784974
fk1y97mvmdu8f select * from test where object_id=:x                1             4 Y N N      1357081020
fk1y97mvmdu8f select * from test where object_id=:x                2             4 Y Y Y      2473784974
fk1y97mvmdu8f select * from test where object_id=:x                3             1 Y Y Y      1357081020
這樣重複的執行下來,oracle就會找到可以被重複使用是幾種執行計劃,並把他們共享出去


ACS相關的檢視
select child_number,predicate,range_id,low,high from v$sql_cs_selectivity         
where sql_id='fk1y97mvmdu8f' order by 1;  
 CHILD_NUMBER PREDICATE                                     RANGE_ID LOW        HIGH
------------- ---------------------------------------- ------------- ---------- ----------
            2 =X                                                   0 0.000018   0.000022
            3 =X                                                   0 0.892941   1.091373
統計的各個子游標的選擇性範圍            


select child_number,bind_set_hash_value,peeked,executions,rows_processed,buffer_gets                        
from v$sql_cs_statistics where sql_id='fk1y97mvmdu8f'                                                       
order by 1;


 CHILD_NUMBER BIND_SET_HASH_VALUE P    EXECUTIONS ROWS_PROCESSED   BUFFER_GETS
------------- ------------------- - ------------- -------------- -------------
            0          2251692860 Y             1              2             5
            1           336594526 Y             1        1380000        110576
            2          1059637539 Y             1              2             5
            3           336594526 Y             1           1411           111
統計的各個子游標的執行情況


 
 
 
 
 
 
關於oracle收集直方圖時 method_opt中引數 auto跟skewonly的區別:




我們先來看官方文件中對這兩個引數的解釋
- AUTO : Oracle determines the columns to collect histograms based on data distribution and the workload of the columns.
- SKEWONLY : Oracle determines the columns to collect histograms based on the data distribution of the columns
從字面上解讀,AUTO和SKEWONLY的區別就在於收集histograms時ORACLE的選擇條件不同。
AUTO會根據column資料分佈情況以及column的負載情況進行判斷是不是收集這個column的histogram.
而SKEWONLY只會根據column的資料分佈情況決定是否收集histogram。
這裡,我會強調這個“只”字,因為在SKEWONLY時,只要Oracle覺得資料分佈可能不均,就會收集列的柱狀圖。
而AUTO時,即使某一個column它的資料分佈不均,但只要這個column的workload很低,或者說沒有workload,那麼Oracle就不會收集這個column的histogram
Oracle自行判斷的依據就來源於col_usage$字典基表,若表上的某一列曾在硬解析(hard parse)過的SQL語句中充當過predicate(通俗的說就是where後的condition)的話,我們認為此列上有收集柱狀圖的必要,那麼col_usage$上就會被加入該列曾充當predicate的記錄。當DBMS_STATS.GATHER_TABLE_STATS儲存過程以’SIZE AUTO’模式執行時,收集程式會檢查col_usage$基表以判斷哪些列之前曾充當過predicate,若充當過則說明該列有收集柱狀圖的價值。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-2131162/,如需轉載,請註明出處,否則將追究法律責任。

相關文章