Oracle數據庫的性能視圖幾乎可以說(shuō)是最引以為驕傲的功能,在那樣細粒度的采樣統計強度下,依然保持卓越的性能,基于這些性能數據采樣之后形成的AWR,更是Oracle DBA分析數據庫性能問(wèn)題的最重要手段之一。
那么在譽(yù)為最接近Oracle的開(kāi)源數據庫PostgreSQL中,如果要診斷性能問(wèn)題,又有哪些視圖可以使用呢?作為Oracle DBA,在學(xué)習PostgreSQL的時(shí)候,不可避免地會(huì )將PostgreSQL和Oracle進(jìn)行比較。
以下SQL命令,在mydb=#提示符下的均為在PostgreSQL中執行的,在SQL>提示符下的均為在Oracle中執行的。
先看一下在PostgreSQL中存在那些統計信息視圖。PostgreSQL中數據字典的命名還是很規范的,所有統計信息基本上都以pg_stat_開(kāi)頭。
mydb=# select relname from pg_class where relname like 'pg_stat_%'; relname ---------------------------------- pg_statistic pg_stats pg_stat_all_tables pg_stat_xact_all_tables pg_stat_sys_tables pg_stat_xact_sys_tables pg_stat_user_tables pg_stat_xact_user_tables pg_statio_all_tables pg_statio_sys_tables pg_statio_user_tables pg_statio_all_indexes pg_statio_sys_indexes pg_statio_user_indexes pg_statio_all_sequences pg_statio_sys_sequences pg_statio_user_sequences pg_stat_activity pg_stat_replication pg_stat_database pg_stat_database_conflicts pg_stat_user_functions pg_stat_xact_user_functions pg_stat_archiver pg_stat_bgwriter pg_stat_all_indexes pg_stat_sys_indexes pg_stat_user_indexes pg_statistic_relid_att_inh_index(29 rows)pg_stat_activity該視圖顯示了連接入一個(gè)Cluster下所有數據庫的會(huì )話(huà)的統計信息,每個(gè)會(huì )話(huà)一行記錄,類(lèi)似于Oracle中的V$SESSION視圖。
pg_stat_activity.query字段直接顯示了該會(huì )話(huà)正在執行的SQL或者上次執行的SQL語(yǔ)句文本。在Oracle中檢查一個(gè)會(huì )話(huà)正在執行的SQL語(yǔ)句文本,則需要通過(guò)V$SESSION和V$SQL視圖Join才可以。
pg_stat_activity.pid字段直接顯示了該會(huì )話(huà)在操作系統上的進(jìn)程ID,這樣通過(guò)top命令看到的繁忙操作系統進(jìn)程,可以很簡(jiǎn)單地通過(guò)該字段定位,來(lái)作進(jìn)一步的診斷。在Oracle中則需要通過(guò)V$SESSION和V$PROCESS視圖Join才可以。
pg_stat_archiver
該視圖始終只有一條記錄,顯示了負責一個(gè)cluster下所有數據庫的重做日志(PostgreSQL中稱(chēng)為WAL file)歸檔進(jìn)程的統計信息,記錄項比較簡(jiǎn)單。last_archived_wal和last_archived_time分別顯示了最近一次歸檔的文件名和最近一次歸檔時(shí)間。
類(lèi)似于Oracle中的V$ARCHIVE_DEST_STATUS。由于PostgreSQL中的歸檔實(shí)現實(shí)在是太簡(jiǎn)單了,所以幾乎跟Oracle沒(méi)有太多可比性。
pg_stat_bgwriter
該視圖始終只有一條記錄,顯示了負責一個(gè)cluster下所有數據庫的后臺寫(xiě)進(jìn)程的統計信息,也就是在操作系統中看到的postgres: writer process。該進(jìn)程每隔bgwriter_delay初始化參數定義的間隔(默認200ms)會(huì )喚醒,將Buffer Pool中修改過(guò)的頁(yè)寫(xiě)入到磁盤(pán)。跟Oracle的后臺進(jìn)程DBWR非常相仿。
在Oracle中沒(méi)有專(zhuān)門(mén)記錄DBWR進(jìn)程的性能視圖,V$BGPROCESS視圖也同樣沒(méi)有提供類(lèi)似的信息,但是在V$SYSSTAT卻記錄了DBWR的統計信息,這部分跟pg_stat_bgwriter中記錄的信息相仿。Oracle 11gR2中有超過(guò)600項的統計信息記錄在V$SYSSTAT視圖中。
select NAME,VALUE from v$sysstat where upper(name) like '%DBWR%';
NAME VALUE ----------flash cache insert skip: DBWR overloaded 0DBWR checkpoint buffers written 1564210DBWR thread checkpoint buffers written 0DBWR tablespace checkpoint buffers written 2852DBWR parallel query checkpoint buffers written 0DBWR object drop buffers written 324DBWR transaction table writes 81619DBWR undo block writes 485016DBWR revisited being-written buffer 0DBWR lru scans 0DBWR checkpoints 4158DBWR fusion writes 0
12 rows selected.pg_stat_database
該視圖對于每個(gè)database顯示一行記錄,PostgreSQL中的Cluster類(lèi)似于Oracle的一個(gè)Instance,一個(gè)Cluster下可以創(chuàng )建多個(gè)database。
該視圖中記錄了每個(gè)數據庫提交了多少事務(wù),回滾了多少事務(wù),讀了多少數據塊,查詢(xún)、插入、更新、刪除了多少記錄(在PostgreSQL中用Tuple這個(gè)奇怪的詞表示跟Row相同的概念),產(chǎn)生過(guò)多少死鎖??傊@是一個(gè)數據庫級別相對很簡(jiǎn)單的統計信息。
但是,在Oracle中還真沒(méi)有與此類(lèi)似的性能視圖,實(shí)際上Oracle沒(méi)有一個(gè)視圖簡(jiǎn)單地記錄了一個(gè)Schema下面總共查詢(xún)或者DML了多少條記錄,但是卻有DBA_TAB_MODIFICATIONS這樣的視圖詳細記錄每一張表的DML數量。查詢(xún)了多少數據?可能Oracle認為這個(gè)數字是太不重要了,或者說(shuō)實(shí)在是太大了,完全沒(méi)必要記錄。
對于事務(wù)級別的統計,同樣可以在Oracle的V$SYSSTAT視圖中查詢(xún)包含“ROLLBACK”和“COMMIT”字樣的統計值,遠比PostgreSQL中記錄地要更多樣。
pg_stat_all_tables/pg_stat_sys_tables/pg_stat_user_tables
在PostgreSQL的統計信息視圖中,all表示一個(gè)數據庫下所有的表,sys表示所有的系統表,user表示所有用戶(hù)創(chuàng )建的表,這三個(gè)配套的視圖我們放在一起看。以下類(lèi)似的也相同。
該視圖對于每張表顯示一條記錄,顯示了一張表上進(jìn)行過(guò)多少全表掃描,多少索引掃描,查詢(xún)、插入、更新、刪除過(guò)多少記錄,表中現在有多少記錄,表的分析時(shí)間等。
在Oracle中表的分析信息存儲在DBA_TABLES中,而對于每個(gè)表上DML的信息如前所述,可以從DBA_TAB_MODIFICATIONS視圖中查詢(xún),而經(jīng)歷過(guò)怎樣的IO則又可以從V$SEGSTAT視圖中查詢(xún)。好吧,實(shí)際上,在Oracle中根本也不關(guān)注一個(gè)表上讀取過(guò)多少記錄這樣的數字,所以在PostgreSQL中但凡跟Tuple相關(guān)的統計值在Oracle中都找不到對應的記錄。對于Oracle來(lái)說(shuō),IO都以Block為單位,所以讀取一條記錄還是讀取一個(gè)塊,在IO消耗上沒(méi)有區別。而至于對于返回記錄數等的優(yōu)化,則歸結到SQL層面,那則可以通過(guò)V$SQLSTAT等一系列視圖作更詳細的分析。
Oracle在視圖層面從Table概念和Segment概念上做了詳細的區分,看似復雜,實(shí)際清晰而且詳盡,而在PostgreSQL中則混為一談了,當然在PostgreSQL中通過(guò)后面會(huì )談到的pg_statio_系列視圖又對表和索引上的IO統計信息進(jìn)行了記錄。
pg_stat_xact_all_tables/pg_stat_xact_sys_tables/pg_stat_xact_user_tables
該系列視圖與上述相仿,只是增加了xact前綴,xact表示transaction,統計的是當前會(huì )話(huà)對于表操作的信息,這部分信息通常還沒(méi)有更新到pg_stat_all_tables視圖中。
在Oracle中由于性能數據的抓取粒度是如此之細,所以并未區分當前會(huì )話(huà)還是已經(jīng)結束的會(huì )話(huà),要知道V$SEGSTAT中的信息幾乎是real-time在更新的。所以,在Oracle中無(wú)需此類(lèi)視圖。
pg_stat_all_indexes/pg_stat_sys_indexes/pg_stat_user_indexes
該視圖對于每個(gè)索引顯示一條記錄,顯示的信息如下:
mydb=# select * from pg_stat_all_indexes where relname='t1'; relid | indexrelid | schemaname | relname | indexrelname | idx_scan | idx_tup_read | idx_tup_fetch -------+------------+------------+---------+--------------+----------+--------------+--------------- 24604 | 24613 | public | t1 | t1_index | 3 | 58960 | 47817(1 row)可見(jiàn)記錄的信息非常簡(jiǎn)單,就是一個(gè)索引上進(jìn)行過(guò)多少次掃描,通過(guò)這個(gè)索引掃描讀取了多少記錄,返回了多少記錄。
在Oracle中,由于索引是Segment的一種,因此類(lèi)似的統計信息都可以從V$SEGSTAT中獲取。
pg_statio_all_tables/pg_statio_sys_tables/pg_statio_user_tables
pg_statio_all_indexes/pg_statio_sys_indexes/pg_statio_user_indexes
這兩部分放在一起描述,具有statio前綴的視圖顯示的是表或索引在數據塊級別的IO統計信息,而stat前綴的視圖(如前面看到的)則顯示的是表或索引在記錄級別的IO統計信息。以pg_statio_all_indexes為例:
mydb=# select * from pg_statio_all_indexes where relname='t1'; relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit -------+------------+------------+---------+--------------+---------------+-------------- 24604 | 24613 | public | t1 | t1_index | 150 | 453(1 row)顯示了讀取過(guò)多少個(gè)數據塊,這些讀取中有多少數據塊是直接命中緩存的。
在Oracle中是我們提到了多次的V$SEGSTAT視圖。
pg_statio_all_sequences/pg_statio_sys_sequences/pg_statio_user_sequencesPostgreSQL對sequence上的IO獨立給出了一系列視圖,PostgreSQL中的sequence跟Oracle中的sequence概念基本一致,為存儲序列號等的字段生成序列值。
該視圖對于每個(gè)序列顯示一條記錄,顯示的信息如下:
mydb=# select * from pg_statio_all_sequences;
relid | schemaname | relname | blks_read | blks_hit -------+------------+--------------+-----------+---------- 24614 | public | users_id_seq | 1 | 3(1 row)非常簡(jiǎn)單,顯示了讀取過(guò)多少個(gè)數據塊,多少數據塊的讀取是直接命中緩存的。
在Oracle中,由于序列是系統自身對象的一部分,因此如果要診斷跟序列相關(guān)的問(wèn)題,通常要依賴(lài)等待事件,比如“enq: SQ – contention”或者“row cache lock”,另外在V$ROWCACHE視圖中存儲了與序列相關(guān)的整體統計值。
SQL> select PARAMETER,GETS,GETMISSES from v$rowcache where PARAMETER='dc_sequences';
PARAMETER GETS GETMISSES-------------------------------- ---------- ----------dc_sequences 2145 54pg_stat_user_functions/pg_stat_xact_user_functions有xact前綴和沒(méi)有前綴的區別在前面描述pg_stat_xact_all_tables系列視圖時(shí)已經(jīng)提過(guò),因此放在一起描述。
該視圖對于每個(gè)指定要跟蹤的用戶(hù)自定義函數顯示一條記錄,這通過(guò)初始化參數track_functions來(lái)控制,默認不開(kāi)啟任何跟蹤,視圖結構如下:
mydb=# \d pg_stat_user_functions
View "pg_catalog.pg_stat_user_functions" Column | Type | Modifiers ------------+------------------+----------- funcid | oid | schemaname | name | funcname | name | calls | bigint | total_time | double precision | self_time | double precision | calls字段記錄了對于用戶(hù)函數進(jìn)行過(guò)多少次調用;
total_time字段記錄了運行這個(gè)函數總共消耗了多長(cháng)時(shí)間(毫秒為單位),包括調用其它函數的時(shí)間;
self_time字段記錄了運行這個(gè)函數本身消耗了多長(cháng)時(shí)間(毫秒為單位),不包括調用其它函數的時(shí)間。
Oracle中沒(méi)有類(lèi)似的視圖,Oracle的關(guān)于函數或者存儲過(guò)程的執行統計信息,都是詳細到其中每一條SQL語(yǔ)句的,實(shí)際上如果像PostgreSQL這樣能有一個(gè)函數或者存儲過(guò)程級別的性能統計值,也是極好的。
pg_stat_replication
在設置了復制的環(huán)境中,該視圖對于每個(gè)WAL sender進(jìn)程(WAL sender進(jìn)程負責將本機的重做日志發(fā)送到遠端復制環(huán)境)顯示一條記錄,顯示內容大致如下:
postgres=# select pid,application_name,client_addr,state,sent_location,replay_location from pg_stat_replication; pid | application_name | client_addr | state | sent_location | replay_location -------+------------------+----------------+-----------+---------------+----------------- 27855 | walreceiver | 192.168.56.105 | streaming | 0/50188CE8 | 0/50188CE8(1 row)每個(gè)視圖中都能直接顯示操作系統進(jìn)程ID,實(shí)在是很方便的事情。在操作系統上可以直接查看pid=27855的進(jìn)程。
[]postgres 27855 1119 0 00:45 ? 00:00:00 postgres: wal sender process postgres 192.168.56.105(57046) streaming 0/50188CE8從操作系統的ps命令中看到實(shí)際上已經(jīng)將視圖中的這些字段內容更新到了該進(jìn)程描述中,在進(jìn)程描述中會(huì )更新一些很有用的信息(比如server進(jìn)程的狀態(tài),是等待還是空閑等),這也是PostgreSQL非常方便的一個(gè)地方。
在Oracle中與PostgreSQL的復制相類(lèi)似的功能是Physical Data Guard,在DG中重做日志的傳輸是通過(guò)歸檔路徑來(lái)完成的,因此類(lèi)似的信息可以從V$ARCHIVE_DEST_STATUS和V$MANAGED_STANDBY視圖中獲取。
pg_stat_database_conflicts
該視圖僅對于Standby數據庫有效,對于每個(gè)數據庫顯示一條記錄,顯示內容如下:
postgres=# select * from pg_stat_database_conflicts; datid | datname | confl_tablespace | confl_lock | confl_snapshot | confl_bufferpin | confl_deadlock -------+-----------+------------------+------------+----------------+-----------------+---------------- 1 | template1 | 0 | 0 | 0 | 0 | 0 13051 | template0 | 0 | 0 | 0 | 0 | 0 13056 | postgres | 0 | 0 | 0 | 0 | 0 16384 | mydb | 0 | 0 | 0 | 0 | 0 24587 | mydb_bak | 0 | 0 | 0 | 0 | 0(5 rows)由于PostgreSQL的機制,在備庫上的查詢(xún)會(huì )跟一些諸如刪除表空間、刪除數據庫、vacuum cleanup的操作相沖突,為了不讓備庫的WAL replay操作延時(shí)太久,PostgreSQL內建了強制取消當前備庫上運行的查詢(xún)以避免跟應用重做日志這樣更重要的動(dòng)作相沖突的機制。而該視圖則是記錄由于不同原因取消掉的查詢(xún)的次數。對于每個(gè)數據庫顯示一條記錄。
Oracle中不會(huì )出現這樣的問(wèn)題,因此也沒(méi)有相應的視圖。
總結
當然,PostgreSQL中除了這些統計信息視圖之外,還有不少類(lèi)似于pg_tables,pg_users這樣與Oracle中的數據字典視圖相仿的視圖,另外還有比如pg_locks這樣用于記錄鎖信息的診斷視圖。但是僅僅用一篇文章的長(cháng)度就可以將所有的統計信息視圖全部介紹完畢,PostgreSQL確實(shí)是很簡(jiǎn)潔的數據庫。
張樂(lè )奕
ACOUG聯(lián)合創(chuàng )始人,Oracle ACE總監
蓋國強:從 Oracle 到 PostgreSQL :從 Uptime 到數據庫實(shí)例運行時(shí)間
編輯:尹文敏
聯(lián)系客服