Oracle的統計信息包括哪幾種類型?程序員
Oracle數據庫裏的統計信息是一組存儲在數據字典裏,且從多個維度描述了數據庫裏對象的詳細信息的一組數據。當Oracle數據庫工做在CBO(Cost Based Optimization,基於代價的優化器)模式下時,優化器會根據數據字典中記錄的對象的統計信息來評估SQL語句的不一樣執行計劃的成本,從而找到最優或者是相對最優的執行計劃。因此,能夠說,SQL語句的執行計劃由統計信息來決定,若沒有統計信息則會採起動態採樣的方式來生成執行計劃。統計信息決定着SQL的執行計劃的正確性,屬於SQL執行的指導思想。若統計信息不許確,則會致使表的訪問方式(例如應該使用索引,可是選擇了全表掃描)、表與表的鏈接方式出現問題(例如應該使用HJ,可是使用了NL鏈接),從而致使CBO選擇錯誤的執行計劃。面試
統計信息主要包括6種類型,其中表、列和索引的統計信息也能夠統稱爲普通對象的統計信息,以下所示:sql
查詢表統計信息的SQL以下所示:數據庫
1SELECT D.NUM_ROWS, --表中的記錄數
2 D.BLOCKS, --轟中數據所佔的數據塊數
3 D.EMPTY_BLOCKS, --表中的空塊數
4 D.AVG_SPACE, --數據塊中平均的,使用空間
5 D.CHAIN_CNT, --表中行鏈接和行遷移的數量
6 D.AVG_ROW_LEN, --每條記錄的平均長度
7 D.STALE_STATS, --統計信息是否過時
8 D.LAST_ANALYZED --最近一次蒐集統計信息的時間
9 FROM DBA_TAB_STATISTICS D --DBA_TAB_STATISTICS DBA_TABLES
10 WHERE D.TABLE_NAME = 'CUSTOMERS';
查詢表上列的統計信息的SQL以下所示:服務器
1SELECT D.COLUMN_NAME,
2 D.NUM_DISTINCT, --惟一值的個數
3 D.LOW_VALUE, --列上的最小值
4 D.HIGH_VALUE, --列上的最大值
5 D.DENSITY, --若不存在柱狀圖的話,則表示選擇率因子(密度)=1/(NDV)
6 D.NUM_NULLS, --空值的個數
7 D.NUM_BUCKETS, --直方圖的BUCKETS個數
8 D.HISTOGRAM --直方圖的類型
9 FROM DBA_TAB_COLUMNS D --DBA_TAB_COL_STATISTICS
10 WHERE TABLE_NAME = 'CUSTOMERS';
關於上表中須要注意的幾點:微信
(一)索引統計信息網絡
BLEVEL存儲的就是目標索引的層級,它表示的是從根節點到葉子塊的深度,BLEVEL被CBO用於計算訪問索引葉子塊的成本。BLEVEL的值越大,則從根節點到葉子塊所須要訪問的數據塊的數量就會越多,耗費的I/O就會越多,訪問索引的成本就會越大。BLEVEL的值從0開始算起,當BLEVEL的值爲0時,表示該B樹索引只有一層,且根節點和葉子塊就是同一個塊。在Oracle數據庫裏,若是要下降目標B樹索引的層級,那麼只能經過REBUILD該索引的方式來實現。app
(二)列的統計信息ide
列的統計信息用於描述Oracle數據庫裏列的詳細信息,包含了列的DISTINCT值的數量、列的NULL值的數量、列的最小值、列的最大值等一些典型維度。這些列統計信息其實是存儲在數據字典基表SYS.HIST_HEAD$中,能夠經過數據字典DBA_TAB_COL_STATISTICS、DBA_PART_COL_STATISTICS和DBA_SUBPART_COL_STATISTICS來分別查看錶、分區表的分區和分區表的子分區的列統計信息。在這些數據字典中的字段NUM_DISTINCT存儲的就是目標列的DISTINCT值的數量。CBO用NUM_DISTINCT的值來評估用目標列作等值查詢的可選擇率(Selectivity)。CBO會用NUM_NULLS的值來調整對有NULL值的目標列作等值查詢的可選擇率。函數
數據字典中的字段DENSITY和NUM_BUCKETS分別存儲的是目標列的密度和所用桶的數量,這兩個維度僅和直方圖有關。在沒有直方圖統計信息時,DENSITY的值就等於I/NUM_DISTINCT;在有頻率直方圖的時,DENSITY的值就等於1/(2*(NUM_ROWS-NUM_NULLS))。示例以下:
1CREATE TABLE T_MD_20170606_LHR AS SELECT ROWNUM ID,ROWNUM SAL FROM DUAL CONNECT BY LEVEL<=10000;
2UPDATE T_MD_20170606_LHR SET SAL=5000 WHERE SAL BETWEEN 6 AND 9995; --9990
3UPDATE T_MD_20170606_LHR SET SAL='' WHERE SAL BETWEEN 2 AND 3; --2
在無直方圖的狀況下:
1LHR@orclasm > EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_MD_20170606_LHR',CASCADE=>TRUE,METHOD_OPT=>'FOR ALL COLUMNS SIZE 1');
2
3PL/SQL procedure successfully completed.
4
5LHR@orclasm > SET LINESIZE 120
6LHR@orclasm > SELECT D.COLUMN_NAME,D.NUM_DISTINCT,D.NUM_NULLS,D.NUM_BUCKETS,D.HISTOGRAM,D.DENSITY FROM DBA_TAB_COLUMNS D WHERE D.TABLE_NAME = 'T_MD_20170606_LHR';
7
8
9COLUMN_NAME NUM_DISTINCT NUM_NULLS NUM_BUCKETS HISTOGRAM DENSITY
10------------------------------ ------------ ---------- ----------- --------------- ----------
11SAL 9 2 1 NONE .111111111
12ID 10000 0 1 NONE .0001
13
14LHR@orclasm > SELECT 1/9,1/10000 FROM DUAL;
15
16 1/9 1/10000
17---------- ----------
18.111111111 .0001
在有直方圖的狀況下:
1LHR@orclasm > EXEC DBMS_STATS.GATHER_TABLE_STATS(USER,'T_MD_20170606_LHR',CASCADE=>TRUE,METHOD_OPT=>'FOR COLUMNS SAL SIZE 9');
2
3PL/SQL procedure successfully completed.
4
5LHR@orclasm > SELECT D.COLUMN_NAME,D.NUM_DISTINCT,D.NUM_NULLS,D.NUM_BUCKETS,D.HISTOGRAM,D.DENSITY FROM DBA_TAB_COLUMNS D WHERE D.TABLE_NAME = 'T_MD_20170606_LHR';
6
7COLUMN_NAME NUM_DISTINCT NUM_NULLS NUM_BUCKETS HISTOGRAM DENSITY
8------------------------------ ------------ ---------- ----------- --------------- ----------
9SAL 9 2 9 FREQUENCY .00005001
10ID 10000 0 1 NONE .0001
11
12LHR@orclasm > SELECT 1/(2*(10000-2)) FROM DUAL;
13
141/(2*(10000-2))
15---------------
16 .00005001
數據字典中的字段LOW_VALUE和HIGH_VALUE分別存儲的就是目標列的最小值和最大值,CBO用LOW_VALUE和HIGH_VALUE來評估對目標列作範圍查詢時的可選擇率。不過這兩個字段的返回值是RAW類型的,須要轉換後才能識別。可使用UTL_RAW.CAST_TO_NUMBER、UTL_RAW.CAST_TO_VARCHAR2等函數來轉換,也可使用存儲過程DBMS_STATS.CONVERT_RAW_VALUE來轉換,下面給出示例:
1CREATE OR REPLACE FUNCTION FUN_DISPLAY_RAW_LHR(P_RAWVAL RAW,P_TYPE VARCHAR2)
2 RETURN VARCHAR2 IS
3 V_NUMBER NUMBER;
4 V_VARCHAR2 VARCHAR2(32);
5 V_DATE DATE;
6 V_NVARCHAR2 NVARCHAR2(32);
7 V_ROWID ROWID;
8 V_CHAR CHAR(32);
9BEGIN
10 IF (P_TYPE = 'NUMBER' OR P_TYPE = 'FLOAT') THEN
11 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_NUMBER);
12 RETURN TO_CHAR(V_NUMBER);
13 ELSIF (P_TYPE = 'VARCHAR2') THEN
14 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_VARCHAR2);
15 RETURN TO_CHAR(V_VARCHAR2);
16 ELSIF (P_TYPE = 'DATE' OR P_TYPE LIKE 'TIMESTAMP%') THEN
17 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_DATE);
18 RETURN TO_CHAR(V_DATE);
19 ELSIF (P_TYPE = 'NVARCHAR2') THEN
20 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_NVARCHAR2);
21 RETURN TO_CHAR(V_NVARCHAR2);
22 ELSIF (P_TYPE = 'ROWID') THEN
23 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_ROWID);
24 RETURN TO_CHAR(V_ROWID);
25 ELSIF (P_TYPE = 'CHAR') THEN
26 DBMS_STATS.CONVERT_RAW_VALUE(P_RAWVAL, V_CHAR);
27 RETURN TO_CHAR(V_CHAR);
28 ELSIF (P_TYPE = 'RAW') THEN
29 RETURN TO_CHAR(P_RAWVAL);
30 ELSE
31 RETURN 'UNKNOWN DATATYPE!';
32 END IF;
33EXCEPTION
34 WHEN OTHERS THEN
35 RETURN 'ERRORS!';
36END FUN_DISPLAY_RAW_LHR;
使用該函數查詢:
1CREATE TABLE T_AA_20170606_LHR AS SELECT * FROM DBA_OBJECTS;
2EXEC DBMS_STATS.gather_table_stats(USER,'T_AA_20170606_LHR');
3SELECT D.COLUMN_NAME,
4 D.LOW_VALUE,
5 D.HIGH_VALUE,
6 D.DENSITY,
7 D.NUM_DISTINCT,
8 D.NUM_NULLS,
9 D.NUM_BUCKETS,
10 D.HISTOGRAM,
11 D.DATA_TYPE,
12 FUN_DISPLAY_RAW_LHR(D.LOW_VALUE, D.DATA_TYPE) LOW_VALUE1,
13 FUN_DISPLAY_RAW_LHR(D.HIGH_VALUE, D.DATA_TYPE) HIGH_VALUE1--,
14 --UTL_RAW.CAST_TO_NUMBER(D.LOW_VALUE) LOW_VALUE2,
15 --UTL_RAW.CAST_TO_NUMBER(D.HIGH_VALUE) HIGH_VALUE2,
16 FROM USER_TAB_COLS D
17 WHERE D.TABLE_NAME = 'T_AA_20170606_LHR';
& 說明:
有關轉換的更多內容能夠參考個人BLOG:http://blog.itpub.net/26736162/viewspace-2140335/
(三)系通通計信息
系通通計信息主要包括目標數據庫服務器CPU的主頻、單塊讀的平均耗費時間、多塊讀的平均耗費時間和單次多塊讀所能讀取的數據塊的平均值等。收集系通通計信息的方法主要是使用系統存儲過程:
1EXEC DBMS_STATS.GATHER_SYSTEM_STATS('start');
2系統正常負載運行一段時間
3EXEC DBMS_STATS.GATHER_SYSTEM_STATS('stop');
4
或:
1EXEC DBMS_STATS.GATHER_SYSTEM_STATS(GATHERING_MODE => 'INTERVAL',INTERVAL =>1);--INTERVAL爲間隔時長,單位爲分鐘
系通通計信息主要存儲在SYS.AUX_STATS$表中,也可使用DBMS_STATS.GET_SYSTEM_STATS獲取系通通計信息的內容,修改系通通計信息可使用DBMS_STATS.SET_SYSTEM_STATS,刪除系通通計信息可使用DBMS_STATS.DELETE_SYSTEM_STATS。
在未引入系通通計信息以前,CBO所計算的成本值所有是基於I/O來計算的;在Oracle引入了系通通計信息以後,實際上就額外地引入了CPU成本計算模型(CPU Cost model),今後之後,CBO所計算的成本值就包括I/O Cost和CPU Cost這兩個部分。CBO在計算成本的時候就會分別對它們各自計算,並將算出來的I/O Cost和CPU Cost值的總和做爲目標SQL新的成本值。
從Oracle 9i開始,Oracle經過一個隱含參數「_OPTIMIZER_COST_MODEL」來控制是否開啓CPU Cost model。該參數的默認值爲CHOOSE,意思是若是SYS.AUX_STATS$表裏有相關記錄,那麼表示開啓CPU Cost model,不然就仍是沿用之前的成本計算模型(即計算的成本所有是I/O Cost)。
1SYS@orclasm > set pagesize 9999
2SYS@orclasm > set line 9999
3SYS@orclasm > col NAME format a40
4SYS@orclasm > col KSPPDESC format a50
5SYS@orclasm > col KSPPSTVL format a20
6SYS@orclasm > SELECT a.INDX,
7 2 a.KSPPINM NAME,
8 3 a.KSPPDESC,
9 4 b.KSPPSTVL
10 5 FROM x$ksppi a,
11 6 x$ksppcv b
12 7 WHERE a.INDX = b.INDX
13 8 and lower(a.KSPPINM) like lower('%¶meter%');
14Enter value for parameter: _OPTIMIZER_COST_MODEL
15old 8: and lower(a.KSPPINM) like lower('%¶meter%')
16new 8: and lower(a.KSPPINM) like lower('%_OPTIMIZER_COST_MODEL%')
17
18 INDX NAME KSPPDESC KSPPSTVL
19---------- ---------------------------------------- -------------------------------------------------- --------------------
20 1917 _optimizer_cost_model optimizer cost model CHOOSE
21
22SYS@orclasm > SET LINESIZE 9999
23SYS@orclasm > COL PVAL1 FOR 999999999
24SYS@orclasm > COL PVAL2 FOR A30
25SYS@orclasm > COL SNAME FOR A15
26SYS@orclasm > SELECT * FROM SYS.AUX_STATS$;
27
28SNAME PNAME PVAL1 PVAL2
29--------------- ------------------------------ ---------- ------------------------------
30SYSSTATS_INFO STATUS COMPLETED
31SYSSTATS_INFO DSTART 06-02-2017 13:54
32SYSSTATS_INFO DSTOP 06-02-2017 13:55
33SYSSTATS_INFO FLAGS 0
34SYSSTATS_MAIN CPUSPEEDNW 1752
35SYSSTATS_MAIN IOSEEKTIM 10
36SYSSTATS_MAIN IOTFRSPEED 4096
37SYSSTATS_MAIN SREADTIM 4
38SYSSTATS_MAIN MREADTIM
39SYSSTATS_MAIN CPUSPEED 2099
40SYSSTATS_MAIN MBRC
41SYSSTATS_MAIN MAXTHR
42SYSSTATS_MAIN SLAVETHR
結果含義以下所示:
l CPUSPEEDNW:非工做量統計模式下CPU主頻,即每秒能夠完成的機器指命數據,直接來自硬件。
l IOSEEKTIM:I/O尋址時間(毫秒),默認值爲10,直接來自硬件。
l IOTFRSPEED:I/O傳輸速率(字節/毫秒),默認爲4096。
l SREADTIM:讀取單個數據塊的平均時間,單位是毫秒(ms)。
l MREADTIM:讀取多個數據塊的平均時間,單位是毫秒(ms)。
l CPUSPEED:工做量統計模式下CPU主頻,根據當前工做量評估出一個合理值。
l MBRC:Oracle收集完統計信息後評估出的一次多塊讀能夠讀幾個數據塊(DB_FILE_MULTIBLOCK_READ_COUNT)。
l MAXTHR:最大I/O吞吐量(字節/秒)。
l SLAVETHR:單個並行進程的最大吞吐量(字節/秒)。
l SYSSTATS_INFO:系通通計信息的狀態和收集時間。
l SYSSTATS_MAIN:系通通計信息的結果集。
l SYSSTATS_TEMP:只有當收集系通通計信息時纔可用。
如下是10053事件的trace關於系統統計數據的部分內容:
1-----------------------------
2SYSTEM STATISTICS INFORMATION
3-----------------------------
4 Using NOWORKLOAD Stats
5 CPUSPEEDNW: 3097 millions instructions/sec (default is 100)
6 IOTFRSPEED: 4096 bytes per millisecond (default is 4096)
7 IOSEEKTIM: 16 milliseconds (default is 10)
8 MBRC: -1 blocks (default is 16)
(四)內部對象統計信息
數據字典基表SYS.TAB_STATS$中會存儲X$表的表對象統計信息。默認狀況下(包括默認的自動統計信息收集做業在內),Oracle不會對X$系列表收集內部對象統計信息,因此默認狀況下SYS.TAB_STATS$中沒有任何記錄。
須要注意的是,X$表雖然只是內存結構,不佔用數據庫的物理存儲空間,但X$系列表的內部對象統計信息實際上已經被Oracle存儲在了數據字典裏,這些統計信息是佔用了實際的物理存儲空間的,這意味着X$表的統計信息已經被持久化了,並不會隨着數據庫的起停而消失。因此,實際上並不須要隨着數據庫的起停而對X$表反覆收集內部對象統計信息,除非系統的負載發生了很大的變化,以前收集的內部對象統計信息已經再也不具有表明性。
即便相關的X$表沒有內部對象統計信息,Oracle也不會在訪問這些X$表時使用動態採樣。在明確診斷出系統已有的性能問題是由於X$表的內部對象統計信息不許引發的,這個時候就應該收集X$表的內部對象統計信息,其它情形就不要收集了。由於X$表實際上就是內存結構,因此在RAC環境下收集內部對象統計信息時須要在每一個節點都進行收集統計信息。
本文選自《Oracle程序員面試筆試寶典》,做者:小麥苗
詳細內容能夠添加麥老師微信或QQ私聊。
● 本文做者:小麥苗,只專一於數據庫的技術,更注重技術的運用
● 做者博客地址:http://blog.itpub.net/26736162/abstract/1/
● 本系列題目來源於做者的學習筆記,部分整理自網絡,如有侵權或不當之處還請諒解
● 版權全部,歡迎分享本文,轉載請保留出處
● QQ:646634621 QQ羣:618766405
● 提供OCP、OCM和高可用部分最實用的技能培訓
● 題目解答如有不當之處,還望各位朋友批評指正,共同進步
長按下圖識別二維碼或微信掃描下圖二維碼來關注小麥苗的微信公衆號:xiaomaimiaolhr,學習最實用的數據庫技術。
本文分享自微信公衆號 - DB寶(lhrdba)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。