MathJax

MathJax-2

MathJax-3

Google Code Prettify

置頂入手筆記

EnterproseDB Quickstart — 快速入門筆記

由於考慮採用 EnterpriseDB 或是直接用 PostgreSQL 的人,通常需要一些入手的資料。這邊紀錄便提供相關快速上手的簡單筆記 ~ 這篇筆記以 資料庫安裝完畢後的快速使用 為目標,基本紀錄登入使用的範例:

2022年9月26日 星期一

抓出 PGSQL 使用暫存表的 Session PID

 PGSQL 的暫存表(temp table)跟 Oracle 不同:PGSQL 的暫存表是 DB Session 私用的;暫存表的生命週期只在 Session 活動期間,登出後就在資料庫裡完全消失。

因此有時候遇到稍微惱人的使用狀況,像是開了很大的暫存表,或是活的很久的暫存表(常駐 AP 咬住的 DB Session),有辦法找出 DB Session 對應的暫存表的話,就蠻有用處的~


首先先了解一下 PGSQL 的暫存表構造
  • temp table 暫存表跟 temp file 暫存檔不同,暫存表相當於真實表格
  • 暫存檔 temp file 是在 SQL 執行過程中產生(CTE materialization、Sorting、external Merge Disk 等發生時);而暫存表 temp table 是自己執行 CREATE TEMP TABLE 指令產生的表格物件
  • 暫存檔的實體檔案,會放置在 $PGDATA/base/pgsql_temp/ 底下;而暫存表則待在普通表格之中(藏樹於林),不過檔名是以 t<NNN>_FFF 的格式(這部份敘述在 PGSQL 手冊的 Database File Layout 章節)
  • 暫存表的 namespace(也就是 schema)主要是指定在 pg_temp_<NNN> 這樣的隱藏 schema 底下(有趣的是,這個資訊在手冊上著墨處不多,比較明確的是列在 search_path 這個 GUC 的說明頁面)
  • 上述的 <NNN>,在 PGSQL 內部稱為 backend ID(這得要在幾份資料之間兜一下才會確認到的資訊),這跟 pg_stat_activity 會看得到的 PID 不一樣。

直接搜尋有關資料,比較明顯的內容是 PGSQL 的衍伸產品 GPDB 在 pg_stat_activity 有提供 sess_id 欄位呈現。
以及,從 OS 與 PID 的關係,有辦法透過 lsof 找出檔案對應的 open flie PID:Postgres 查找 Temp Table 建立者 - Postgres 筆記 - Ken

不過,要湊出純 PGSQL 手法的尋找方式,得作一點繞道。
  1. 首先,要先釐清 PGSQL 的 backend ID
  2. 要確認 backend ID 怎麼跟 PID 對上
  3. 透過 temp schema 命名方式,在 pg_class 或 pg_stat_user_tables 找出暫存表
  4. 把上面的東西 JOIN 在一起

找了一陣子,總算是找到 1 跟 2 的方式:這紀錄在兩個隱藏函數 pg_stat_get_backend_pid()pg_stat_get_backend_idset():後者可以抓出當前 PGSQL 全部運作中的 backend ID,而前者可以從 backend ID 對應出 PID。
edb=# -- 這是 set-returning function,兩個前後順序有差
edb=# SELECT bkend_id, bkend_pid
edb-# FROM pg_stat_get_backend_idset() bkend_id,
edb-#      pg_stat_get_backend_pid(bkend_id) bkend_pid;
 bkend_id | bkend_pid
----------+-----------
        1 |     11308
        2 |     11310
        3 |     11311
        4 |     11380
        5 |     11455
        6 |     11306
        7 |     11305
        8 |     11307
(8 rows)

edb=# 

通常對應 PID 最常使用的就是搭配 pg_stat_activity 一起看,這邊紀錄一版。
edb=# SELECT bkend_id, a.*
edb-# FROM pg_stat_get_backend_idset() bkend_id,
edb-#      pg_stat_get_backend_pid(bkend_id) bkend_pid,
edb-#      pg_stat_activity a
edb-# WHERE bkend_pid = a.pid
edb-# AND a.backend_type = 'client backend';
 bkend_id | datid | datname |  pid  | leader_pid | usesysid |   usename    | application_name | client_addr | client_hostname | client_port |          backend_start           |            xact_start            |           query_start            |           state_change           | wait_event_type | wait_event | state  | backend_xid | backend_xmin | query_id |                       query                        |  backend_type
----------+-------+---------+-------+------------+----------+--------------+------------------+-------------+-----------------+-------------+----------------------------------+----------------------------------+----------------------------------+----------------------------------+-----------------+------------+--------+-------------+--------------+----------+----------------------------------------------------+----------------
        4 | 15579 | edb     | 11380 |            |       10 | enterprisedb | psql             |             |                 |          -1 | 26-SEP-22 14:32:25.759978 +00:00 | 26-SEP-22 14:33:31.818314 +00:00 | 26-SEP-22 14:33:31.818314 +00:00 | 26-SEP-22 14:33:31.818318 +00:00 |                 |            | active |             |         2200 |          | SELECT bkend_id, a.*                              +| client backend
          |       |         |       |            |          |              |                  |             |                 |             |                                  |                                  |                                  |                                  |                 |            |        |             |              |          | FROM pg_stat_get_backend_idset() bkend_id,        +|
          |       |         |       |            |          |              |                  |             |                 |             |                                  |                                  |                                  |                                  |                 |            |        |             |              |          |      pg_stat_get_backend_pid(bkend_id) bkend_pid, +|
          |       |         |       |            |          |              |                  |             |                 |             |                                  |                                  |                                  |                                  |                 |            |        |             |              |          |      pg_stat_activity a                           +|
          |       |         |       |            |          |              |                  |             |                 |             |                                  |                                  |                                  |                                  |                 |            |        |             |              |          | WHERE bkend_pid = a.pid                           +|
          |       |         |       |            |          |              |                  |             |                 |             |                                  |                                  |                                  |                                  |                 |            |        |             |              |          | AND a.backend_type = 'client backend';             |
        5 | 15579 | edb     | 11455 |            |       10 | enterprisedb | psql             |             |                 |          -1 | 26-SEP-22 14:32:54.571466 +00:00 |                                  |                                  | 26-SEP-22 14:32:54.577064 +00:00 | Client          | ClientRead | idle   |             |              |          |                                                    | client backend
(2 rows)

edb=#

接著就是湊一下,就可以得到以下的 SQL
SELECT a.pid, bkend_id,
       t.relnamespace::regnamespace, t.relname, t.relfilenode
FROM pg_stat_get_backend_idset() bkend_id,
     pg_stat_get_backend_pid(bkend_id) bkend_pid,
     pg_stat_activity a,
     pg_class t
WHERE bkend_pid=a.pid
AND a.backend_type='client backend'
AND t.relnamespace::regnamespace::text = concat('pg_temp_', bkend_id);

作一點測試:建立 temp table 前/後,以及對照 temp table 的檔名。
edb=# -- 目前 Session 的 PID
edb=# SELECT pg_backend_pid();
 pg_backend_pid
----------------
          10814
(1 row)

edb=# -- 確認一下現在沒有暫存表
edb=# SELECT a.pid, bkend_id,
edb-#        t.relnamespace::regnamespace, t.relname, t.relfilenode
edb-# FROM pg_stat_get_backend_idset() bkend_id,
edb-#      pg_stat_get_backend_pid(bkend_id) bkend_pid,
edb-#      pg_stat_activity a,
edb-#      pg_class t
edb-# WHERE bkend_pid=a.pid
edb-# AND a.backend_type='client backend'
edb-# AND t.relnamespace::regnamespace::text = concat('pg_temp_', bkend_id);
 pid | bkend_id | relnamespace | relname | relfilenode
-----+----------+--------------+---------+-------------
(0 rows)

edb=# 
edb=# -- 開暫存表
edb=# create temp table xx(id int);
CREATE TABLE
edb=# 
edb=# -- 再跑一次就看到了
edb=# SELECT a.pid, bkend_id,
       t.relnamespace::regnamespace, t.relname, t.relfilenode
FROM pg_stat_get_backend_idset() bkend_id,
     pg_stat_get_backend_pid(bkend_id) bkend_pid,
     pg_stat_activity a,
     pg_class t
WHERE bkend_pid=a.pid
AND a.backend_type='client backend'
AND t.relnamespace::regnamespace::text = concat('pg_temp_', bkend_id);
  pid  | bkend_id | relnamespace | relname | relfilenode
-------+----------+--------------+---------+-------------
 10814 |        4 | pg_temp_4    | xx      |       33518
(1 row)

edb=#
edb=# -- 檢視暫存表檔名
edb=# \! ls $PGDATA/base/15579/t*
/var/lib/edb/as14/data/base/15579/t4_33518
edb=# 


完工~注意雖然上面只用相同 session 作檢查,但這個 SQL 只要 superuser,就都可以看其他 session 的狀況~

最後補充:
PGSQL 的 autovacuum 碰不到暫存表:也就是說,若有常駐的 DB session 並且會開著暫存表不斷使用的話,就要留意對暫存表的 VACUUM ANALYZE。
因此這邊的 SQL 可能就有點用處了~留意哪些暫存表變得太老,要調整對應的程式碼。


參考資料
Size of temp tables created in a particular session - Stack Overflow
Where is temporary table created? - Stack Overflow
Postgres 查找 Temp Table 建立者 - Postgres 筆記 - Ken
Temporary files in PostgreSQL – Steps to identify and fix temp file issues - Kloud DB
PostgreSQL temp files usage - DEV Community 👩‍💻👨‍💻
PostgreSQL Mailing List: Quirk of pg_temp schemas ...
PostgreSQL Mailing List: Thread: pg_temp schemas : Postgres Professional
pg_stat_get_backend_pid() - pgPedia - a PostgreSQL Encyclopedia
pg_stat_get_backend_idset() - pgPedia - a PostgreSQL Encyclopedia
有一種罕見的 Transaction ID wraparound 叫做 MxID wraparound,偷偷塞在這邊
PostgreSQL: Documentation: 14: 25.1. Routine Vacuuming - 25.1.5.1. Multixacts And Wraparound
PostgreSQL DBA(158) - Locks(tuple locks)_ITPUB博客
postgres/README.tuplock at master

沒有留言:

張貼留言