CBO與動態統計量取樣
CBO(基於成本的最佳化器)是目前Oracle預設使用的SQL最佳化器方法。最佳化器的作用在於對輸入執行的SQL產生適合的執行路徑。
傳統的RBO(基於規則的最佳化器)是依據一系列預定義規則進行SQL執行計劃生成,會去考慮如SQL語句的結構、where條件和資料表索引情況等。這樣的做雖然簡單,但是不會考慮資料實際情況,很多時候生成高效執行計劃的機率不高。CBO更多的是依據實際資料列的情況,透過公式進行成本試算,這種方式依據的是實際資料表資料列的分佈情況和統計資訊。從實際情況上看,我們透過CBO獲取的執行路徑,更加科學和有效。
本質上看,如果RBO就是一系列規則的集合和匹配機制。那麼CBO就是一系列引數和統計量的公式,不多試算各種執行路徑,之後返回一條Cost最小。那麼,CBO依據的就是資料統計量和預設值的一系列控制引數。
一系列的控制引數,如optimizer_index_cost_adj等,大都都是Oracle的預設設定,通常不需要調整。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Prod
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 – Production
SQL> show parameter adj
NAME TYPE VALUE
------------------------------------ -------
optimizer_index_cost_adj integer 100
另一部分就是對資料物件的統計量資訊。藉助抽樣等方法對資料表物件進行分析,得出統計量,是CBO計算執行成本的另一方面重要因素。
收集統計量,我們可以使用Oracle的dbms_stats包進行統計量收集。
SQL> create table t as select * from dba_objects;
Table created
SQL> create index ind_t_cmp on t(owner,object_name);
Index created
SQL> exec dbms_stats.gather_table_stats(user,'T',cascade => true);
PL/SQL procedure successfully completed
SQL> set autotrace traceonly;
SQL> select * from t where wner='SCOTT' and object_name='EMP';
執行計劃
----------------------------------------------------------
Plan hash value: 1097962935
----------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 93 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 93 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_T_CMP | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT' AND "OBJECT_NAME"='EMP')
統計資訊
----------------------------------------------------------
1 recursive calls
0 db block gets
4 consistent gets
0 physical reads
0 redo size
1202 bytes sent via SQL*Net to client
385 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
SQL>
我們透過執行計劃,可以看出藉助統計量,可以獲取到相對較好的CBO執行計劃。那麼,統計量檢視資訊是存在的,例如:
SQL> col column_name for a20;
SQL> select column_name, NUM_DISTINCT, DENSITY,NUM_NULLS from dba_tab_col_statistics where wner='SYS' and table_name='T';
COLUMN_NAME NUM_DISTINCT DENSITY NUM_NULLS
-------------------- ------------ ---------- ----------
OWNER 20 0.05 0
OBJECT_NAME 30086 3.32380509 0
SUBOBJECT_NAME 103 0.00970873 49938
OBJECT_ID 50347 1.98621566 0
DATA_OBJECT_ID 4050 0.00024691 46252
OBJECT_TYPE 29 0.03448275 0
CREATED 1354 0.00073855 0
LAST_DDL_TIME 1366 0.00073206 0
TIMESTAMP 1357 0.00073691 0
STATUS 2 0.5 0
TEMPORARY 2 0.5 0
GENERATED 2 0.5 0
SECONDARY 1 1 0
13 rows selected
透過檢視,我們可以看到資料表T對應資料列的一些基本統計資訊(篇幅原因,其他一些統計量省略),包括密度、分佈情況和空值等資訊。此外還有對執行計劃影響重要的直方圖資訊。這些引數都會在CBO的成本計算公式中進入計算範疇。
一個疑問就出現了。我們現在是使用了顯示的dbms_stats方法,收集統計量。那麼如果我們沒有收集統計量,建立資料後直接進行查詢,Oracle CBO依據的統計資料怎麼獲取呢?我們進行下列的實驗。
SQL> create table t2 as select * from dba_objects;
Table created
SQL> create index ind_t2_cmp on t2(owner,object_name);
Index created
SQL> select column_name, NUM_DISTINCT, DENSITY,NUM_NULLS from dba_tab_col_statistics where wner='SYS' and table_name='T2';
COLUMN_NAME NUM_DISTINCT DENSITY NUM_NULLS
-------------------- ------------ ---------- ----------
我們沒有對資料表T2進行任何顯示的統計量收集。統計量檢視dba_tab_col_statistics中沒有對應的任何統計資訊。此時,我們進行查詢。
SQL> select * from t2 where wner='SCOTT' and object_name='EMP';
執行計劃
----------------------------------------------------------
Plan hash value: 3661878964
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 177 | 2 (0)|00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 177 | 2 (0)|00:00:01 |
|* 2 | INDEX RANGE SCAN | IND_T2_CMP | 1 | | 1 (0)|00:00:01 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OWNER"='SCOTT' AND "OBJECT_NAME"='EMP')
Note
-----
- dynamic sampling used for this statement
統計資訊
----------------------------------------------------------
254 recursive calls
0 db block gets
(篇幅原因,略…)
1 rows processed
結果,我們發現,雖然沒有顯示的進行統計量收集。Oracle執行計劃還是生成了,CBO還為我們找出了相對較好的一條路徑。唯一需要注意的就是標註:“- dynamic sampling used for this statement”。
原來,Oracle在這裡採用了一種“動態取樣”技術才應對這種情況。詳細過程猜想是這樣:在沒有進行統計量收集的時候,Oracle執行對一個資料表的執行計劃生成。一旦發現沒有對應的統計量資訊,就會開始一個動態取樣收集的過程,用相對較低的取樣率收集資料表統計量。最後根據這些收集結果生成執行計劃。
當然,Oracle認為這樣的情況是一種特殊情況,並不推薦。原因主要在於動態收集要兼顧執行效率(畢竟是佔用SQL執行的時間),所以抽樣率和其他準確度不會很高。對一些資料量很大的資料表,取樣率高意味著準確,但同時也意味著時間長。所以,Oracle對這種動態取樣結果是不推薦的。
那麼,是不是對於Oracle資料表,我們依賴動態取樣的結果就好了呢?答案是否定的。首先,動態取樣的結果抽樣率低,不準確。這個已經提過,一些很大的資料表,為了提高效率還是保證一定的抽樣比例較好。其次,動態取樣的結果是不記錄如資料字典的。也就是動態的結果生成執行計劃即可,下次執行的時候還會進行動態收集。這樣得不償失。
//沒有計入資料字典任何資訊
SQL> select column_name, NUM_DISTINCT, DENSITY,NUM_NULLS from dba_tab_col_statistics where wner='SYS' and table_name='T2';
COLUMN_NAME NUM_DISTINCT DENSITY NUM_NULLS
-------------------- ------------ ---------- ----------
//顯示進行收集!
SQL> exec dbms_stats.gather_table_stats(user,'T2',cascade => true);
PL/SQL procedure successfully completed
SQL> select column_name, NUM_DISTINCT, DENSITY,NUM_NULLS from dba_tab_col_statistics where wner='SYS' and table_name='T2';
COLUMN_NAME NUM_DISTINCT DENSITY NUM_NULLS
-------------------- ------------ ---------- ----------
OWNER 24 9.94954676 0
(篇幅原因,省略…)
SUBOBJECT_NAME 103 0.00970873 49940
SECONDARY 2 0.5 0
13 rows selected
最後,我們簡單說說收集統計量的方法問題。從上面的實驗可以看出,Oracle進入CBO時代後,對統計量的依存度很高。那麼,保證統計量的方法是什麼呢?就需要定期的進行全庫物件的統計量收集。這個方面,Oracle提供了“自動統計量收集”的功能。
從10g開始,Oracle預設(11g中允許選擇)會新增一條自動作業專案。在每天晚上10點開始進行資料統計量收集的工作。這樣就利用業務處理量相對較少的時段進行自動的統計量收集。
當然,這樣也給一些7×24小時的系統帶來一些困擾。本來想利用夜間進行一些報表作業或者處理,結果發現比白天還慢。這樣可能就需要去除掉這個功能了,這方面網路上介紹很多,本文就不累述了。
如果沒有采用自動收集策略,就需要DBA進行指令碼方式的收集工作。
無論是何種方式,越精準、越有代表性的統計量,就越可能生成高效的執行計劃,提高整體的效能。通常,因為統計量的異常,是引起SQL執行效能的重要原因。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/17203031/viewspace-689043/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle 動態取樣Oracle
- 關於ORACLE自動統計CBO統計資訊Oracle
- Oracle動態取樣分析Oracle
- 臨時表(GLOBAL TEMPORARY TABLE)及統計資訊收集,動態取樣
- Oracle 執行計劃 分析和動態取樣Oracle
- Oracle 分析及動態取樣Oracle
- Oracle動態取樣學習Oracle
- 【sql調優】動態取樣SQL
- 關於ORACLE自動統計CBO統計資訊[轉帖]Oracle
- 對於沒有任何統計資訊的表,ORACLE可能會動態取樣。Oracle
- 微課sql最佳化(6)、統計資訊收集(4)-關於動態取樣SQL
- ORACLE10g自動收集CBO統計資訊Oracle
- Oracle 分析及動態取樣(轉帖)Oracle
- 如何找出使用動態取樣的SQLSQL
- dbms_stats.lock_table_stats與動態取樣(Dynamic Sampling)
- 【AWR】測試AWR手動取樣對系統自動取樣的影響
- 如何檢視哪些SQL使用了動態取樣?SQL
- 【原創】ORACLE 資料分析和動態取樣Oracle
- 雞肋 -- ORACLE10g自動收集CBO統計資訊(ZT)Oracle
- oracle動態取樣_optimizer_dynamic_samplingOracle
- 示例說明動態取樣的作用,並演示動態取樣對有內在關係的多列查詢的影響
- [zt] Oracle10g 自動收集收集CBO統計資訊設定Oracle
- Oracle CBO 與 RBOOracle
- 【cbo計算公式】CBO基本概念(一)公式
- oracle動態取樣_optimizer_dynamic_sampling(二)Oracle
- sql profile禁用oracle動態取樣dynamic samplingSQLOracle
- [Oracle] Oracle收集統計資訊的取樣比例Oracle
- 動態生成DOM元素的高度及行數獲取與計算方法
- 計量系統的設計與實施
- CBO成本計算初探
- lit動態修改樣式
- rabbitMq實現系統內的簡訊傳送設計&動態獲取BEANMQBean
- 9i,10g 優化器動態取樣級別引數 -- optimizer_dynamic_sampling (統計優化)優化
- php動態獲取常量PHP
- 蘇州能源計量檢測與能效統計管理系統
- 動態變更vue樣式Vue
- javascript 動態修改css樣式JavaScriptCSS
- 系統設計架構:有狀態與無狀態架構