支援的版本: 目前 (17) / 16 / 15 / 14 / 13
開發版本: devel
不支援的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4

F.30. pg_stat_statements — 追蹤 SQL 規劃與執行的統計資訊 #

pg_stat_statements 模組提供了一種追蹤伺服器執行的所有 SQL 陳述式的規劃與執行統計資訊的方法。

必須將 pg_stat_statements 新增至 shared_preload_librariespostgresql.conf 以載入此模組,因為它需要額外的共享記憶體。這表示需要重新啟動伺服器才能新增或移除此模組。此外,必須啟用查詢識別符計算,此模組才能運作,如果 compute_query_id 設定為 autoon,或者載入了任何計算查詢識別符的協力廠商模組,則會自動執行此動作。

pg_stat_statements 啟用時,它會追蹤伺服器所有資料庫的統計資訊。若要存取和操作這些統計資訊,此模組提供了檢視 pg_stat_statementspg_stat_statements_info,以及公用程式函數 pg_stat_statements_resetpg_stat_statements。這些並非全域可用,但可以使用 CREATE EXTENSION pg_stat_statements 為特定資料庫啟用。

F.30.1. pg_stat_statements 檢視 #

此模組收集的統計資訊可透過名為 pg_stat_statements 的檢視取得。此檢視針對資料庫 ID、使用者 ID、查詢 ID 和是否為最上層陳述式的每種不同組合包含一個資料列(最多可追蹤的相異陳述式數量上限)。檢視的欄位顯示在 表格 F.21 中。

表格 F.21. pg_stat_statements 欄位

欄位 類型

描述

userid oid(參考 pg_authid.oid

執行陳述式的使用者 OID

dbid oid(參考 pg_database.oid

執行陳述式的資料庫 OID

toplevel bool

如果查詢以最上層陳述式執行,則為 True(如果 pg_stat_statements.track 設定為 top,則永遠為 true)

queryid bigint

用於識別相同標準化查詢的雜湊碼。

query text

代表性陳述式的文字

plans bigint

陳述式被規劃的次數(如果啟用 pg_stat_statements.track_planning,否則為零)

total_plan_time double precision

規劃陳述式的總時間,以毫秒為單位(如果啟用 pg_stat_statements.track_planning,否則為零)

min_plan_time double precision

規劃陳述式所花費的最短時間,以毫秒為單位。如果停用了 pg_stat_statements.track_planning,或者如果使用 pg_stat_statements_reset 函數重置了計數器,並且 minmax_only 參數設定為 true 且從未規劃過,則此欄位將為零。

max_plan_time double precision

規劃陳述式所花費的最長時間,以毫秒為單位。如果停用了 pg_stat_statements.track_planning,或者如果使用 pg_stat_statements_reset 函數重置了計數器,並且 minmax_only 參數設定為 true 且從未規劃過,則此欄位將為零。

mean_plan_time double precision

規劃陳述式所花費的平均時間,以毫秒為單位(如果啟用 pg_stat_statements.track_planning,否則為零)

stddev_plan_time double precision

規劃陳述式所花費時間的母體標準差,以毫秒為單位(如果啟用 pg_stat_statements.track_planning,否則為零)

calls bigint

陳述式被執行的次數

total_exec_time double precision

執行陳述式的總時間,以毫秒為單位

min_exec_time double precision

執行陳述式所花費的最短時間,以毫秒為單位。在執行過 pg_stat_statements_reset 函數且 minmax_only 參數設定為 true 後,這個欄位在首次執行陳述式前會是零。

max_exec_time double precision

執行陳述式所花費的最長時間,以毫秒為單位。在執行過 pg_stat_statements_reset 函數且 minmax_only 參數設定為 true 後,這個欄位在首次執行陳述式前會是零。

mean_exec_time double precision

執行陳述式所花費的平均時間,以毫秒為單位。

stddev_exec_time double precision

執行陳述式所花費時間的母體標準差,以毫秒為單位。

rows bigint

陳述式檢索或影響的總列數。

shared_blks_hit bigint

陳述式命中的共享區塊快取的總數。

shared_blks_read bigint

陳述式讀取的共享區塊總數。

shared_blks_dirtied bigint

陳述式弄髒的共享區塊總數。

shared_blks_written bigint

陳述式寫入的共享區塊總數。

local_blks_hit bigint

陳述式命中的本地區塊快取的總數。

local_blks_read bigint

陳述式讀取的本地區塊總數。

local_blks_dirtied bigint

陳述式弄髒的本地區塊總數。

local_blks_written bigint

陳述式寫入的本地區塊總數。

temp_blks_read bigint

陳述式讀取的暫存區塊總數。

temp_blks_written bigint

陳述式寫入的暫存區塊總數。

shared_blk_read_time double precision

陳述式花費在讀取共享區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

shared_blk_write_time double precision

陳述式花費在寫入共享區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

local_blk_read_time double precision

陳述式花費在讀取本地區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

local_blk_write_time double precision

陳述式花費在寫入本地區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

temp_blk_read_time double precision

陳述式花費在讀取臨時檔案區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

temp_blk_write_time double precision

陳述式花費在寫入臨時檔案區塊的總時間,以毫秒為單位(如果啟用 track_io_timing,否則為零)。

wal_records bigint

陳述式產生的 WAL 記錄總數。

wal_fpi bigint

陳述式產生的 WAL 完整頁面影像總數。

wal_bytes numeric

陳述式產生的 WAL 總量,以位元組為單位。

jit_functions bigint

陳述式 JIT 編譯的函數總數。

jit_generation_time double precision

陳述式花費在產生 JIT 程式碼的總時間,以毫秒為單位。

jit_inlining_count bigint

函數被內聯的次數。

jit_inlining_time double precision

陳述式花費在內聯函數的總時間,以毫秒為單位。

jit_optimization_count bigint

陳述式被優化的次數。

jit_optimization_time double precision

陳述式花費在優化的總時間,以毫秒為單位。

jit_emission_count bigint

程式碼被發出的次數。

jit_emission_time double precision

陳述式花費在發出程式碼的總時間,以毫秒為單位。

jit_deform_count bigint

陳述式 JIT 編譯的 tuple deform 函數總數。

jit_deform_time double precision

陳述式花費在 JIT 編譯 tuple deform 函數的總時間,以毫秒為單位。

stats_since timestamp with time zone

開始收集此陳述式統計資料的時間。

minmax_stats_since timestamp with time zone

開始收集此陳述式最小/最大統計資料的時間 (欄位 min_plan_time, max_plan_time, min_exec_timemax_exec_time)。


基於安全理由,只有超級使用者和具有 pg_read_all_stats 角色權限的角色才能看到其他使用者執行的查詢的 SQL 文字和 queryid。但是,如果視窗已安裝在他們的資料庫中,其他使用者可以看到統計資料。

當可規劃的查詢(也就是 SELECTINSERTUPDATEDELETEMERGE)和公用程式命令根據內部雜湊計算具有相同的查詢結構時,它們會合併為單個 pg_stat_statements 項目。通常,如果兩個查詢在語義上等效,但查詢中出現的文字常數值除外,則會將它們視為相同。

注意

以下有關常數替換和 queryid 的詳細資訊僅在啟用 compute_query_id 時適用。如果您改用外部模組來計算 queryid,則應參閱其文件以取得詳細資訊。

當常數的值已被忽略,以便將查詢與其他查詢匹配時,該常數將被 pg_stat_statements 顯示中的參數符號(例如 $1)替換。查詢文字的其餘部分是第一個查詢的文字,該查詢具有與 pg_stat_statements 項目關聯的特定 queryid 雜湊值。

pg_stat_statements 中可能會觀察到可以應用哪些正規化的查詢具有常數值,尤其是在條目解除配置率很高時。為了降低這種情況發生的可能性,請考慮增加 pg_stat_statements.max。 下文 第 F.30.2 節討論的 pg_stat_statements_info 檢視表提供了有關條目解除配置的統計資訊。

在某些情況下,具有明顯不同文字的查詢可能會合併到單個 pg_stat_statements 條目中。 通常,這只會發生在語義上等效的查詢中,但存在雜湊碰撞導致不相關的查詢合併為一個條目的小機率(但是,這不會發生於屬於不同使用者或資料庫的查詢)。

由於 queryid 雜湊值是在查詢的剖析後分析表示式上計算的,因此相反的情況也可能發生:如果具有相同文字的查詢由於諸如不同的 search_path 設定等因素而具有不同的含義,則它們可能會顯示為單獨的條目。

pg_stat_statements 的使用者可能希望使用 queryid(可能與 dbiduserid 結合使用)作為每個條目比其查詢文字更穩定和可靠的識別符號。 但是,重要的是要理解,對於 queryid 雜湊值的穩定性只有有限的保證。 由於識別符號是從剖析後分析樹衍生出來的,因此它的值是此表示式中出現的內部物件識別符號的函數,以及其他因素。 這有一些違反直覺的含義。 例如,如果兩個查詢引用在兩個查詢的執行之間被刪除並重新建立的表,則 pg_stat_statements 會認為兩個表面上相同的查詢是不同的。 雜湊處理過程也對機器架構和平台的其他方面差異很敏感。 此外,不能假定 queryidPostgreSQL 的主要版本之間是穩定的。

期望參與基於實體 WAL 重播的複寫的兩個伺服器對於同一查詢具有相同的 queryid 值。 但是,邏輯複寫方案不保證副本在所有相關細節上都相同,因此 queryid 不會成為跨一組邏輯副本累積成本的有用識別符號。 如果有疑問,建議直接測試。

通常,可以假定 queryid 值在 PostgreSQL 的次要版本發布之間是穩定的,前提是實例在同一機器架構上執行,並且目錄中繼資料詳細資訊匹配。 只有在萬不得已的情況下,才會在次要版本之間打破相容性。

用於替代表徵性查詢文字中常數的參數符號從原始查詢文字中最高 $n 參數後的下一個數字開始,如果沒有,則從 $1 開始。 值得注意的是,在某些情況下,可能存在影響此編號的隱藏參數符號。 例如,PL/pgSQL 使用隱藏的參數符號將函數區域變數的值插入到查詢中,因此 PL/pgSQL 語句(如 SELECT i + 1 INTO j)將具有如 SELECT i + $2 這樣的代表性文字。

代表性查詢文字保存在外部磁碟檔案中,並且不佔用共享記憶體。 因此,即使是很長的查詢文字也可以成功儲存。 但是,如果累積了許多長查詢文字,則外部檔案可能會變得難以管理地龐大。 如果發生這種情況,作為一種恢復方法,pg_stat_statements 可以選擇捨棄查詢文字,之後 pg_stat_statements 檢視表中的所有現有條目都將顯示空值 query 欄位,但與每個 queryid 相關聯的統計資訊會被保留。 如果發生這種情況,請考慮減少 pg_stat_statements.max 以防止再次發生。

由於計畫和執行統計資訊是在各自的結束階段更新的,並且僅適用於成功的操作,因此 planscalls 並不總是預期匹配。 例如,如果成功計畫了一個語句,但在執行階段失敗,則僅更新其計畫統計資訊。 如果因為使用了快取的計畫而跳過了計畫,則僅更新其執行統計資訊。

F.30.2. pg_stat_statements_info 檢視表 #

pg_stat_statements 模組本身的統計資訊會被追蹤,並透過名為 pg_stat_statements_info 的檢視表提供。 此檢視表僅包含單列。 檢視表的欄位顯示在 表格 F.22 中。

表格 F.22. pg_stat_statements_info 欄位

欄位 類型

描述

dealloc bigint

因為觀察到的不同語句多於 pg_stat_statements.max,所以關於執行次數最少的語句的 pg_stat_statements 條目總共被解除配置的次數

stats_reset timestamp with time zone

pg_stat_statements 檢視表中所有統計資訊上次重設的時間。


F.30.3. 函數 #

pg_stat_statements_reset(userid Oid, dbid Oid, queryid bigint, minmax_only boolean) returns timestamp with time zone

pg_stat_statements_reset 會捨棄 pg_stat_statements 到目前為止所收集的統計資料,這些資料對應於指定的 useriddbidqueryid。 如果任何參數未指定,則每個參數都會使用預設值 0 (無效),並且會重置與其他參數匹配的統計資料。 如果未指定任何參數或所有指定的參數都是 0 (無效),則會捨棄所有統計資料。 如果 pg_stat_statements 視窗中的所有統計資料都被捨棄,也會重置 pg_stat_statements_info 視窗中的統計資料。 當 minmax_onlytrue 時,只會重置最小和最大規劃及執行時間的值 (即 min_plan_timemax_plan_timemin_exec_timemax_exec_time 欄位)。 minmax_only 參數的預設值為 false。 上次執行最小/最大重置的時間顯示在 pg_stat_statements 視窗的 minmax_stats_since 欄位中。 此函數會傳回重置的時間。 如果實際上執行了相應的重置,此時間會儲存到 pg_stat_statements_info 視窗的 stats_reset 欄位,或是 pg_stat_statements 視窗的 minmax_stats_since 欄位。 預設情況下,只有超級使用者才能執行此函數。 可以使用 GRANT 授予其他人存取權。

pg_stat_statements(showtext boolean) returns setof record

pg_stat_statements 視窗是根據一個也名為 pg_stat_statements 的函數來定義的。 用戶端可以直接呼叫 pg_stat_statements 函數,並且透過指定 showtext := false 來省略查詢文字 (也就是說,對應於視窗 query 欄位的 OUT 引數將會傳回 null)。 此功能旨在支援可能希望避免重複擷取不確定長度的查詢文字的外部工具。 由於 pg_stat_statements 本身只會執行此操作,因此這些工具可以快取每個條目首次觀察到的查詢文字,然後僅在需要時才擷取查詢文字。 由於伺服器將查詢文字儲存在檔案中,因此此方法可能會減少重複檢查 pg_stat_statements 資料的實際 I/O。

F.30.4. 組態參數 #

pg_stat_statements.max (integer)

pg_stat_statements.max 是模組追蹤的最大陳述式數量 (即 pg_stat_statements 視窗中的最大列數)。 如果觀察到的不同陳述式多於此數量,則會捨棄有關執行次數最少的陳述式的資訊。 可以在 pg_stat_statements_info 視窗中看到此類資訊被捨棄的次數。 預設值為 5000。 此參數只能在伺服器啟動時設定。

pg_stat_statements.track (enum)

pg_stat_statements.track 控制模組計算哪些陳述式。 指定 top 以追蹤最上層陳述式 (由用戶端直接發出的陳述式),指定 all 以同時追蹤巢狀陳述式 (例如在函數中呼叫的陳述式),或指定 none 以停用陳述式統計資料收集。 預設值為 top。 只有超級使用者才能變更此設定。

pg_stat_statements.track_utility (boolean)

pg_stat_statements.track_utility 控制模組是否追蹤公用程式命令。 公用程式命令是指除了 SELECTINSERTUPDATEDELETEMERGE 之外的所有命令。 預設值為 on。 只有超級使用者才能變更此設定。

pg_stat_statements.track_planning (boolean)

pg_stat_statements.track_planning 控制模組是否追蹤規劃操作和持續時間。 啟用此參數可能會導致明顯的效能降低,尤其是當具有相同查詢結構的陳述式由許多並行連線執行時,這些連線會競爭更新少量 pg_stat_statements 條目。 預設值為 off。 只有超級使用者才能變更此設定。

pg_stat_statements.save (boolean)

pg_stat_statements.save 指定是否在伺服器關機時儲存陳述式統計資料。 如果是 off,則統計資料不會在關機時儲存,也不會在伺服器啟動時重新載入。 預設值為 on。 此參數只能在 postgresql.conf 檔案中或在伺服器命令列上設定。

此模組需要與 pg_stat_statements.max 成比例的額外共用記憶體。 請注意,無論何時載入模組,都會消耗此記憶體,即使 pg_stat_statements.track 設定為 none 也是如此。

這些參數必須在 postgresql.conf 中設定。 一般用法可能是

# postgresql.conf
shared_preload_libraries = 'pg_stat_statements'

compute_query_id = on
pg_stat_statements.max = 10000
pg_stat_statements.track = all

F.30.5. 範例輸出 #

bench=# SELECT pg_stat_statements_reset();

$ pgbench -i bench
$ pgbench -c10 -t300 bench

bench=# \x
bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2
calls           | 3000
total_exec_time | 25565.855387
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------​------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 4 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 5 ]---+--------------------------------------------------​------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000


bench=# SELECT pg_stat_statements_reset(0,0,s.queryid) FROM pg_stat_statements AS s
            WHERE s.query = 'UPDATE pgbench_branches SET bbalance = bbalance + $1 WHERE bid = $2';

bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_tellers SET tbalance = tbalance + $1 WHERE tid = $2
calls           | 3000
total_exec_time | 20756.669379
rows            | 3000
hit_percent     | 100.0000000000000000
-[ RECORD 2 ]---+--------------------------------------------------​------------------
query           | copy pgbench_accounts from stdin
calls           | 1
total_exec_time | 291.865911
rows            | 100000
hit_percent     | 100.0000000000000000
-[ RECORD 3 ]---+--------------------------------------------------​------------------
query           | UPDATE pgbench_accounts SET abalance = abalance + $1 WHERE aid = $2
calls           | 3000
total_exec_time | 271.232977
rows            | 3000
hit_percent     | 98.8454011741682975
-[ RECORD 4 ]---+--------------------------------------------------​------------------
query           | alter table pgbench_accounts add primary key (aid)
calls           | 1
total_exec_time | 160.588563
rows            | 0
hit_percent     | 100.0000000000000000
-[ RECORD 5 ]---+--------------------------------------------------​------------------
query           | vacuum analyze pgbench_accounts
calls           | 1
total_exec_time | 136.448116
rows            | 0
hit_percent     | 99.9201915403032721

bench=# SELECT pg_stat_statements_reset(0,0,0);

bench=# SELECT query, calls, total_exec_time, rows, 100.0 * shared_blks_hit /
               nullif(shared_blks_hit + shared_blks_read, 0) AS hit_percent
          FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT 5;
-[ RECORD 1 ]---+--------------------------------------------------​---------------------------
query           | SELECT pg_stat_statements_reset(0,0,0)
calls           | 1
total_exec_time | 0.189497
rows            | 1
hit_percent     |
-[ RECORD 2 ]---+--------------------------------------------------​---------------------------
query           | SELECT query, calls, total_exec_time, rows, $1 * shared_blks_hit /          +
                |                nullif(shared_blks_hit + shared_blks_read, $2) AS hit_percent+
                |           FROM pg_stat_statements ORDER BY total_exec_time DESC LIMIT $3
calls           | 0
total_exec_time | 0
rows            | 0
hit_percent     |

F.30.6. 作者 #

Takahiro Itagaki 。 Peter Geoghegan 新增的查詢正規化

提交更正

如果您在文件中看到任何不正確、與您使用特定功能的經驗不符或需要進一步澄清的內容,請使用此表單報告文件問題。