CKH 網誌

PostgreSQL 16 監控入門:慢查詢、鎖定與執行計畫實測

實測環境與硬體規格

項目實際測試配置
測試日期2026-10-02
作業系統Ubuntu 24.04.5 LTS
主機數量1 台新建隔離 VM;下列資源為每台配置
CPU2 vCPU
記憶體4 GiB
系統磁碟32 GiB;HDD 儲存、VirtIO、ext4
Linux 核心6.8.0-139-generic
PostgreSQLpsql (PostgreSQL) 16.15 (Ubuntu 16.15-0ubuntu0.24.04.1)

用實際的長查詢與同時執行的交易,觀察連線、找出阻塞來源、解除等待,再比較新增索引前後的執行計畫。

本文以全新 Ubuntu 24.04 隔離主機和合成資料實測。套件來自經過簽章驗證、符合 Noble 的套件來源;沒有使用正式資料庫或正式網站的帳號。讀者請依自己的環境確認來源與版本。

圖中是測試主機實際 bash PTY 的執行紀錄,由瀏覽器呈現;提示符統一為 lab$,執行結果未改寫。文字命令另行保留,方便複製。

開始前需完成 PostgreSQL 16 的原生安裝與叢集啟動,可先閱讀 Ubuntu 24.04 安裝篇。本系列使用 demo 範例資料庫;需要既有 sample 表的篇章,依 搬機篇的資料建立步驟 準備 100 筆合成資料。請在獨立教學環境操作。

一、先看正在執行的連線

本次以管理者檢視統計,並用 application_name 只篩選自己的合成測試工作。正式監控帳號可依需要授予專用監控角色;不應把資料庫超級使用者憑證放到一般網頁。

SELECT application_name, state, wait_event_type, wait_event
FROM pg_stat_activity
WHERE application_name='lab_slow_query';

啟動另一個測試連線執行以下 SQL,便能在 pg_stat_activity 看見真正在等待的查詢。沒有讀取其他使用者的 SQL 或來源 IP,也沒有公開正式查詢內容。

SET application_name='lab_slow_query';
SELECT pg_sleep(30);
圖1:實際長查詢的等待狀態與指定查詢取消
圖1:實際長查詢的等待狀態與指定查詢取消。實際 PTY 紀錄,點圖可開啟原尺寸。

需要結束這個測試時,只取消完全符合自己標籤且不是目前連線的 PID:

SELECT pg_cancel_backend(pid)
FROM pg_stat_activity
WHERE application_name='lab_slow_query'
  AND pid <> pg_backend_pid();

pg_cancel_backend 取消目前查詢,與強制終止整個連線不同。不要把條件拿掉後套到所有 PID;正式環境先核對工作來源與業務影響。管理函式

二、用兩個交易產生真正的鎖等待

開兩個教學連線。連線 A 執行後先保持交易不結束:

SET application_name='lab_blocker';
BEGIN;
UPDATE sample SET note='held' WHERE id=1;

連線 B 更新同一筆資料,這時會等待 A:

SET application_name='lab_waiter';
UPDATE sample SET note='released' WHERE id=1;

再用第三個管理連線查詢:

SELECT application_name, wait_event_type,
       cardinality(pg_blocking_pids(pid)) AS blockers
FROM pg_stat_activity
WHERE application_name IN ('lab_blocker','lab_waiter')
ORDER BY application_name;
圖2:兩個真實交易產生的鎖等待與阻塞來源數
圖2:兩個真實交易產生的鎖等待與阻塞來源數。實際 PTY 紀錄,點圖可開啟原尺寸。

實測等待連線的 wait_event_type 為 Lock,阻塞來源數為 1。在 A 執行 ROLLBACK; 後,B 的 UPDATE 確實完成。測試資料是合成資料,沒有取消或終止其他服務的連線。

三、設定慢查詢門檻並確認真的寫入日誌

ALTER SYSTEM SET log_min_duration_statement='200ms';
SELECT pg_reload_conf();
SELECT pg_sleep(0.3);

本次在 PostgreSQL 16 原生日誌中確認 0.3 秒的合成查詢有 duration 記錄。200ms 是教學門檻,正式環境應依負載和日誌容量調整。慢查詢日誌可能包含 SQL、參數或個人資料;只將允許公開的測試結果摘出,不直接貼原始日誌。

測試完可還原預設設定:

ALTER SYSTEM RESET log_min_duration_statement;
SELECT pg_reload_conf();

四、看執行計畫,不只看是否有索引

CREATE TABLE plan_sample AS
SELECT n AS id, repeat('x',100) AS note FROM generate_series(1,10000) n;
ANALYZE plan_sample;
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM plan_sample WHERE id=5000;
CREATE INDEX plan_sample_id_idx ON plan_sample(id);
EXPLAIN (ANALYZE, BUFFERS)
SELECT * FROM plan_sample WHERE id=5000;

本次 10,000 筆合成資料在建立索引前得到 Seq Scan,建立後得到 Index Scan。這是功能驗證,不能據此宣稱正式工作負載會得到相同加速比。EXPLAIN ANALYZE 會真的執行 SQL,本篇僅使用 SELECT;不要直接拿會寫入資料的 SQL 在正式環境測。

五、讓觀察結果能回答問題

遇到效能問題時,依序確認:是否有正在執行的長查詢、是否等待其他交易、慢查詢是否被記錄、執行計畫是否符合預期。此次實測在解除鎖定後完成更新,重新開機後資料與服務正常。

這次驗證了什麼

驗證項目結果
實際 pg_sleep 在活動統計可見通過
只取消指定測試查詢通過
真實 UPDATE 的阻塞來源數為 1通過
ROLLBACK 後等待的 UPDATE 完成通過
200ms 門檻記錄 0.3 秒測試查詢通過
10,000 筆資料的 Seq Scan/Index Scan 均驗證通過

實測範圍:驗證合成慢查詢、真實交易阻塞、慢查詢日誌與索引前後計畫;不是效能壓測。沒有安裝 Grafana/Prometheus,也沒有承諾特定吞吐量或延遲。

官方參考資料

活動統計、慢查詢日誌、EXPLAIN