23.2. 統計蒐集器

PostgreSQL統計蒐集器是一個支援蒐集和匯報伺服器活躍性訊息的子系統。 目前,這個蒐集器可以給對資料表和索引的訪問計數,包括磁盤塊的數量和獨立行的項。 它還可以判斷目前其它伺服器進程在執行的命令是什麼。

23.2.1. 統計蒐集器配置

因為統計蒐集給查詢處理增加了一些過熱,所以您可以把系統配置為蒐集訊息,也可以配置為不蒐集訊息。 這個是由配置參數控制的,這些配置參數通常在 postgresql.conf 裡設置(參閱 Section 16.4 獲取有關設置配置參數的細節)。

要想讓統計蒐集器執行起來, 參數 stats_start_collector 必須設置為真。 這個設置是預設設置,也是建議設置,但是如果您對統計不感興趣並且想把所有過荷都擠出去, 那麼可以把它設置為假。(不過,省下來的東西並不多。) 請注意這個選項在伺服器執行的時候並不能改變。

參數 stats_command_stringstats_block_level,和 stats_row_level 控制實際發送給蒐集器的數量, 因此也決定了會產生多少執行時過熱。這些選項分別決定一個伺服器進程是否發送它的目前命令字串, 磁盤塊層次的訪問統計,以及行層次的訪問統計給蒐集器。 通常這些參數在 postgresql.conf 中設置, 因此它們適用於所有伺服器進程, 但是我們也可以在獨立的會話裡用 SET 命令把它們打開或者關閉。 (為避免普通用戶把它們的活躍性隱藏不給管理員看,只有超級用戶允許用 SET 命令修改這些參數。)

注意: 因為參數 stats_command_stringstats_block_level,和 stats_row_level 預設時false, 索引實際上預設配置中不蒐集任何統計訊息。 打開這些配置變量中的一個或多個可以顯著增加統計收機器生成的有用訊息的數量,代價是增加了一點執行時開銷。

23.2.2. 查看蒐集到的統計訊息

有一些預定義的視圖可以用於顯示統計蒐集的結果,在 Table 23-1 裡列出。另外, 我們可以使用下層的統計函數製作自己的客戶化視圖。

在使用統計觀察目前活躍性的時候,您必須意識到這些訊息並不是實時更新的。 每個獨立的伺服器進程只是在準備空閒的時候才向蒐集器傳送新的塊和行訪問計數; 因此正在處理的查詢或者交易並不影響顯示出來的總數。 同樣,蒐集器本身也時最多每 pgstat_stat_interval毫秒 (預設是 500)發送一次新的報告。因此顯示的總數總是落後於實際活動。 目前的查詢訊息是立即報告給蒐集器的,但是在其可見之前,仍然受 pgstat_stat_interval 的約束。

另外一個需要著重指出的問題是,在請求伺服器進程顯示任何這些統計訊息的時候, 它首先抓取蒐集器進程發出的最新的報告。然後它就接著拿這些資料作為所有統計視圖和函數的快照, 直到它目前的交易的結束。 因此統計在您目前交易的持續期間內時不會改變的。這是一個特性, 而不是一個毛病,因為這樣就允許您在統計上執行幾個查詢並且對結果進行相關性的檢查而又不用擔心這些數字會背著您變化。 但是如果您想看每個查詢的新的結果,那麼就要記住在任何交易外面處理這些查詢。

Table 23-1. 標準統計視圖

視圖名字描述
pg_stat_activity每個伺服器進程一行,顯示進程ID,資料庫,用戶,目前查詢和目前查詢開始執行的時間。 只有在打開 stats_command_string 參數的時候, 才能得到報告目前查詢的相關訊息的各個字串。 另外,除非檢查這些字串的用戶是超級用戶或者是擁有正在匯報的進程的同一個用戶,否則它們顯示為空。 (請注意因為蒐集器的報告延遲,目前查詢只是對長時間執行的查詢及時更新。)
pg_stat_database每個資料庫一行,顯示激活的後端的數量,提交的交易總數以及在該資料庫中回捲數目的總數, 讀取的磁盤塊的總數,以及緩衝區命中的總數(也就是中所需要的塊已經在緩衝區中找到,從而避免了讀取塊的動作)。
pg_stat_all_tables目前資料庫中每個資料表一行,裡面有順序掃瞄和索引掃瞄的總數, 每種類型的掃瞄返回的資料的總數以及資料插入,更新,和刪除的總數。
pg_stat_sys_tablespg_stat_all_tables一樣,只不過只顯示系統資料表。
pg_stat_user_tablespg_stat_all_tables一樣,只不過只顯示用戶資料表。
pg_stat_all_indexes目前資料庫的每個索引一行,包括使用了該索引的索引掃瞄總數, 索引資料讀取的總數以及成功抓取的堆資料的數目(如果有些索引記錄指向過期的堆資料,那麼這個數目可能少一些。)
pg_stat_sys_indexespg_stat_all_indexes一樣,只不過只包含那些顯示為系統資料表上的索引。
pg_stat_user_indexespg_stat_all_indexes一樣,只不過只包含那些顯示為用戶資料表上的索引。
pg_statio_all_tables目前資料庫中每個資料表一行,包含從該資料表中讀取的磁盤塊總數, 緩衝區命中的總數,在該資料表上所有索引的磁盤塊讀取和緩衝區命中總數, 在該資料表的輔助 TOAST 資料表(如果存在)上的磁盤塊讀取和緩衝區命中總數, 以及 TOAST 資料表的索引的磁盤塊讀取和緩衝區命中總數.
pg_statio_sys_tablespg_statio_all_tables一樣,只不過只顯示系統資料表.
pg_statio_user_tablespg_statio_all_tables一樣,只不過只顯示用戶資料表.
pg_statio_all_indexes目前資料庫中每個索引一行,包含該索引的磁盤塊讀取和緩衝區命中的數目。
pg_statio_sys_indexespg_statio_all_indexes一樣,只不過只顯示系統資料表。
pg_statio_user_indexespg_statio_all_indexes一樣,只不過只顯示用戶資料表。
pg_statio_all_sequences目前資料庫中每個序列對像一個,包含該序列磁盤讀取和緩衝區命中的數目。
pg_statio_sys_sequencespg_statio_all_sequences一樣,只不過只顯示系統序列。 (準確地說,我們沒有定義系統序列,所以這個視圖總是空的。)
pg_statio_user_sequencespg_statio_all_sequences一樣,只不過只顯示用戶序列。

每索引的統計對於判斷哪個索引得到使用以及它們的效果非常有用。

pg_statio_ 系列視圖在判斷緩衝的效果的時候特別有用。 在實際磁盤讀取遠資料表緩衝命中小的時候,我們就知道這個緩衝基本滿足所有讀要求,因此不需要進行內核調用。 但是,這些統計並未給出所有訊息:由於 PostgreSQL 處理磁盤的方式,不在 PostgreSQL 緩衝區緩存的資料可能仍然駐留在內核的 I/O 緩存中, 因此仍然可能不經過實際讀取而抓取。 對獲取 PostgreSQL 的 I/O 行為的更多細節感興趣的用戶可以結合使用 PostgreSQL 的統計蒐集器和可以分析內核 I/O 處理的操作系統工具來獲取更多細節。

其它查看統計的方法可以透過書寫使用下層統計訪問函數的查詢來設置,這些下層統計訪問函數和標準視圖裡使用的是一樣的。 這些函數在Table 23-2 中列出。 就某資料庫進行訪問的函數接受一個資料庫 OID 為參數來標識需要報告哪個資料庫。 就某資料表或者某索引進行訪問的函數接受一個資料表或者索引的 OID。 (請注意這些函數只能看到在目前資料庫裡的資料表和索引)。 就某後端進行訪問的函數接受一個後端 ID 號,其範圍從一到目前活躍後端的數目。

Table 23-2. 統計訪問函數

函數返回類型描述
pg_stat_get_db_numbackends(oid)integer 處理資料庫的活躍的後端進程數目。
pg_stat_get_db_xact_commit(oid)bigint 資料庫中已提交交易數量。
pg_stat_get_db_xact_rollback(oid)bigint 資料庫中回捲的交易數量
pg_stat_get_db_blocks_fetched(oid)bigint 資料庫中磁盤塊抓取請求總數
pg_stat_get_db_blocks_hit(oid)bigint 為資料庫在緩衝區中找到的磁盤塊抓取請求總數
pg_stat_get_numscans(oid)bigint 如果參數是一個資料表,那麼就是進行的順序掃瞄的數目, 如果是一個索引,那麼就是索引掃瞄的數目。
pg_stat_get_tuples_returned(oid)bigint 如果參數是一個資料表,那麼就是順序掃瞄讀取的資料數目, 如果是一個索引,那麼就是索引資料的數目
pg_stat_get_tuples_fetched(oid)bigint 如果參數是一個資料表,那麼就是順序掃瞄抓取的有效(未過期)的資料表資料數目, 如果是一個索引,那麼就是用這個索引抓取的有效資料表資料數目
pg_stat_get_tuples_inserted(oid)bigint 插入資料表中的資料數量
pg_stat_get_tuples_updated(oid)bigint 在資料表中已更新的資料數量
pg_stat_get_tuples_deleted(oid)bigint 從資料表中刪除的資料數量
pg_stat_get_blocks_fetched(oid)bigint 資料表或者索引的磁盤塊抓取請求的數量
pg_stat_get_blocks_hit(oid)bigint 在緩衝區中找到的資料表或者索引的磁盤塊請求數目
pg_stat_get_backend_idset()set of integer 目前活躍後端 ID 的集合(從 1 到活躍後端的數目)。 參閱文本中的使用樣例。
pg_backend_pid()integer 附著在目前會話上的後端進程 ID
pg_stat_get_backend_pid(integer)integer 給出的後端進程的進程號
pg_stat_get_backend_dbid(integer)oid 指定後端進程的資料庫 ID
pg_stat_get_backend_userid(integer)oid 指定後端進程的用戶 ID
pg_stat_get_backend_activity(integer)text 後端進程的目前活躍查詢(如果調用者不是超級用戶,或者不是與被查詢的會話同一個用戶, 或者沒有打開 stats_command_string 則為 NULL)
pg_stat_get_backend_activity_start(integer)timestamp with time zone 指定後端進程目前正在執行的查詢的起始時間(如果目前用戶不是超級用戶,或者 不是與被查詢的會話同一個用戶,或者沒有打開 stats_command_string 則為 NULL)
pg_stat_reset()boolean 重置所有目前蒐集的統計。

注意: pg_stat_get_db_blocks_fetched 減去 pg_stat_get_db_blocks_hit 就是為該資料表,索引或者資料庫 發出的 read() 內核調用的數目;不過實際的實際讀取的數目通常比較低, 因為還有內核級的緩衝。

函數 pg_stat_get_backend_idset 提供了一個為每個活躍後端進程生成一行的便捷的方法。 比如,要顯示所有後端的PID和它們的目前查詢:

SELECT pg_stat_get_backend_pid(s.backendid) AS procpid,
       pg_stat_get_backend_activity(s.backendid) AS current_query
    FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;