Oracle系通通計信息
1. 什麼是系通通計信息?
咱們知道在CBO環境中,Oracle依賴於對象的統計估算成本,以選擇正確的SQL執行計劃。從Oracle9i開始CBO計算成本(cost)的算法有了變化。Oracle9i之前更多考慮IO(多塊讀與單塊讀)成本;9i之後,強化了cpu速度對成本估算的影響。
Oracle提供了dbms_stats.gather_system_stats來收集系通通計信息。系通通計信息讓優化器考慮服務器的IO與CPU性能及其利用率,做爲計算成本的依據;爲每個可選的執行計劃估算IO與CPU成本。於是對於CBO來講,得到準確的系通通計信息對於正確估計成本是很是重要的。Oracle收集的系通通計信息主要內容說明以下:
--cpuspeedNW 表示非負載狀況下的cpu速度,在系統啓動時自動蒐集
--ioseektim
IO查找時間,以毫秒錶示;缺省爲10ms,非負載模式或能夠手動設置。
--iotfrspeed IO傳輸速度,表示Oracle數據庫單次讀數據的傳輸速率,單位爲bytes/ms,在系統啓動時自動收集;默認爲4096 bytes/ms
--cpuspeed
表示負載狀況下的cpu速度,以平均每秒可提供的cpu週期表示
--maxthr 最大IO吞吐量,單位爲bytes/s
--slavethr
從屬IO吞吐量,表示並行進程時,從屬進程的IO吞吐量,單位爲bytes/s
--sreadtim
單塊讀時間(如索引讀取),表示隨機讀一個Oracle數據塊的時間,以ms計算
--mreadtim
多塊讀時間(主要是指全表掃描),表示連續讀取多個Oracle數據庫的平均時間,以ms計算
--mbrc
多塊讀計數,表示一次多塊讀的讀取的Oracle數據塊數量
系通通計信息存儲在sys.aux_stats$表中:
SQL> select * from sys.aux_stats$;
SNAME PNAME PVAL1 PVAL2
-------------------- -------------------- ---------- --------------------
SYSSTATS_INFO STATUS COMPLETED
SYSSTATS_INFO DSTART 01-24-2011 18:06
SYSSTATS_INFO DSTOP 01-24-2011 18:06
SYSSTATS_INFO FLAGS 1
SYSSTATS_MAIN CPUSPEEDNW 1970.048
SYSSTATS_MAIN IOSEEKTIM 11.132
SYSSTATS_MAIN IOTFRSPEED 4096
SYSSTATS_MAIN SREADTIM 6
SYSSTATS_MAIN MREADTIM 24
SYSSTATS_MAIN CPUSPEED 1800
SYSSTATS_MAIN MBRC 6
SNAME PNAME PVAL1 PVAL2
SYSSTATS_MAIN MAXTHR
SYSSTATS_MAIN SLAVETHR
2. 系通通計信息的收集
Dbms_stats.gather_system_stats的參數以下:
SQL> desc dbms_stats.gather_system_stats;
Parameter Type Mode Default?
-------------- -------- ---- --------
GATHERING_MODE VARCHAR2 IN Y
INTERVAL NUMBER IN Y
STATTAB VARCHAR2 IN Y
STATID VARCHAR2 IN Y
STATOWN VARCHAR2 IN Y
STATTAB、STATID、STATOWN與其餘收集統計信息的參數同樣,很少作說明。系通通計信息有工做負載與無工做負載兩種類型; ioseektim、iotrfspeed、cpuspeednw是無負載的統計信息,也就是說不須要系統有工做負載,能夠系統空閒時進行收集。Oracle爲在系統啓動時間從新設置,或重置爲默認值。要手動收集非工做負載統計信息,使用dbms_stats.gather_system_stats(gathering_mode => 'NOWORKLOAD'
)。當使用dbms_stats.delete_system_stats()刪除系通通計信息時間,將只保留非負載時的統計信息:
SQL> exec dbms_stats.delete_system_stats();
PL/SQL
過程已成功完成。
SQL> select * from sys.aux_stats$;
SNAME PNAME PVAL1 PVAL2
-------------------- -------------------- ---------- --------------------
SYSSTATS_INFO STATUS COMPLETED
SYSSTATS_INFO DSTART 01-25-2011 11:37
SYSSTATS_INFO DSTOP 01-25-2011 11:37
SYSSTATS_INFO FLAGS 0
SYSSTATS_MAIN CPUSPEEDNW 2030.679
SYSSTATS_MAIN IOSEEKTIM 10
SYSSTATS_MAIN IOTFRSPEED 4096
SYSSTATS_MAIN SREADTIM
SYSSTATS_MAIN MREADTIM
SYSSTATS_MAIN CPUSPEED
SYSSTATS_MAIN MBRC
SNAME PNAME PVAL1 PVAL2
-------------------- -------------------- ---------- --------------------
SYSSTATS_MAIN MAXTHR
SYSSTATS_MAIN SLAVETHR
已選擇
13
行。
不一樣壓力與不一樣類型的應用,甚至同一系統的不一樣時間,cpu與io的能力都是不同的。好比ZLHIS在8點到11點的壓力,明顯於大於下午的壓力;這時候包括多塊讀時間、單塊讀時間的效率都會有差別。理想的狀況是,收集不一樣系統負載下的系通通計信息,存放到特定的統計信息表中,而後在負載發生變化的時候導入到Oracle中,但在相似ZLHIS這種要求高可用的系統,頻繁的變動系通通計信息不太現實。大多數狀況下,只須要採集系統高峯時段或典型時段的系通通計信息便可。
收集負載狀況下的統計信息有兩種方式,一種是手工指定收集時段的開始與結束:
--
啓動收集
exec
dbms_stats.gather_system_stats(gathering_mode =>
'START'
);
.............
--
等待系統運行一段時間,等待時間長短根據狀況作調整
.............
--
中止收集
exec
dbms_stats.gather_system_stats(gathering_mode =>
'STOP'
);
另外一種方式就是使用間隔模式,指定一個間隔時段,Oracle自動開始與結束信息收集:
--
以將來
10
分鐘的系統負載,收集系通通計信息。
exec dbms_stats.gather_system_stats(gathering_mode => 'INTERVAL',interval => 10);
須要說明的是收集系通通計信息,並不影響已經緩存的sql語句,只會影響新解析的SQL語句,若是要已經緩存的SQL語句也按新的系通通計信息生成執行計劃,只有清空共享池,但這在生產系統上是比較危險的操做。另外須要注意的就是,若是在收集時段內沒有相應操做,將不會收集對應的系通通計信息;例如,若是收集時段內沒有產生全表掃描的多塊讀,mbrc(多塊讀計數)將不會收集。
2. 系通通計信息對CBO成本計算的影響
雖然CBO計算的成本只是對生成何種執行計劃有關,並不對真正執行SQL語句的真實代價產生什麼影響,但做爲CBO估算成本的基礎要素,系通通計信息要儘可能保證準確。咱們經過實驗來講明系通通計信息對sql語句成本估算的影響:
使用dba_objects視圖建立一個測試表:
SQL> --
建立測試表
SQL> create table test as select * from dba_objects;
表已建立。
SQL> insert into test select * from test;
已建立
10212
行。
SQL> --
收集測試表的統計信息
SQL> exec dbms_stats.gather_table_stats(ownname => user,tabname => 'test',cascade => true);
PL/SQL
過程已成功完成。
而後刪除刪除工做負載的統計信息,只保留非工做負載的統計信息
:
exec
dbms_stats.delete_system_stats();
咱們來看此時的對
test
全表掃描估算的成本:
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
71
(0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 |
71
(0)| 00:00:01 |
能夠看到
Oracle
在沒有負載狀況下的系通通計信息時,估算的成本爲
71
。接下爲,咱們使用導入一些系通通計信息。因爲測試環境,沒有什麼負載,咱們使用
dbms_stats.set_system_stats
過程來手工修改統計信息:
SQL> --
建立統計信息表
SQL> exec dbms_stats.create_stat_table(ownname => user,stattab => 'SYSTEM_STATS');
PL/SQL
過程已成功完成。
SQL> --
設置相關的統計信息值
SQL> exec dbms_stats.set_system_stats(pname => 'SREADTIM',pvalue => '6' ,stattab => 'system_stats');
PL/SQL
過程已成功完成。
SQL> exec dbms_stats.set_system_stats(pname => 'MREADTIM',pvalue => '12',stattab => 'system_stats');
PL/SQL
過程已成功完成。
SQL> exec dbms_stats.set_system_stats(pname => 'CPUSPEED',pvalue => '1800' ,stattab => 'system_stats');
PL/SQL
過程已成功完成。
SQL> exec dbms_stats.set_system_stats(pname => 'MBRC',pvalue => '16',stattab => 'system_stats');
PL/SQL
過程已成功完成。
SQL> --
導入相應統計信息
SQL> exec dbms_stats.import_system_stats(stattab => 'system_stats',statown => user);
PL/SQL
過程已成功完成。
如今來從新查看
sql
語句的估算成本:
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 33 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 | 33 (0)| 00:00:01 |
此次估算的成本
(cost)
爲
33,
在收集了系統信息後,
CBO
估算的成本發生了變化。咱們知道
Oracle
提供了db_file_multiblock_read_count參數,來控制Oracle一次多塊讀的Oracle數據塊數量,也將影響Oracle對全表掃描成本的估算
。
Oracle
既然收集了多塊讀
IO
速度
(mreadtim
)
、多塊讀計數
(mbrc)
等信息,那db_file_multiblock_read_count的設置與這些統計信息是什麼關係呢?答案是:若是存在負載狀況下的多塊讀的相關統計信息,將會忽略db_file_multiblock_read_count的設置,若是不存在相應的系通通計信息,將使用db_file_multiblock_read_count的值對全表掃描成本進行估算。
首先,咱們測試一下,不存在相關係通通計信息時,全表掃描的成本:
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
71
(0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 |
71
(0)| 00:00:01 |
-------------------------------------------------------------------
已選擇
9
行。
能夠當作本(cost)又回到了未收集系通通計信息時的71,而不是收集後的33,這個時候,咱們修改db_file_multiblock_read_count參數,來看看相應的成本cost是否會起變化:
SQL> show parameter db_file_multiblock_read_count;
NAME TYPE VALUE
------------------------------------ ----------- ---------------------
db_file_multiblock_read_count integer 8
SQL> alter session set db_file_multiblock_read_count=16;
會話已更改。
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------
--------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
57
(0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 |
57
(0)| 00:00:01 |
-------------------------------------------------------------------
已選擇
9
行。
能夠看到在沒有系通通計信息的狀況下,設置db_file_multiblock_read_count,能夠影響SQL的成本估算,如今變成了57。如今從新導入系通通計信息,看設置db_file_multiblock_read_count可否影響執行計劃:
--
從新導入系通通計信息
SQL> exec dbms_stats.import_system_stats(stattab => 'system_stats',statown => user);
PL/SQL
過程已成功完成。
SQL> --
還原
db_file_multiblock_read_count
SQL> alter session set db_file_multiblock_read_count=8;
會話已更改。
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
33
(0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 |
33
(0)| 00:00:01 |
-------------------------------------------------------------------
已選擇
9
行。
能夠看到,導入系通通計信息後,成本又變成了
33
,咱們再設置
db_file_multiblock_read_count
,再從新解析
sql
語句:
SQL> --
再設置
db_file_multiblock_read_count
值
SQL> alter session set db_file_multiblock_read_count=16;
會話已更改。
SQL> explain plan for select count(*) from test;
已解釋。
SQL> select * from table(dbms_xplan.display());
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------
Plan hash value: 1950795681
-------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
-------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 |
33
(0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| TEST | 20424 |
33
(0)| 00:00:01 |
-------------------------------------------------------------------
已選擇
9
行。
將
db_file_multiblock_read_count
從
8
設置成
16
時,發現估算的成本沒有發生變化。