Oracle的SYSTEM統計信息

 

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 時,發現估算的成本沒有發生變化。
相關文章
相關標籤/搜索