如何“vacuumlo”一個 RDS PostgreSQL 數據庫?
您可能已經註意到,作為一種完全託管的數據庫即服務產品,AWS 關係數據庫服務 (RDS) 限制了使用者態命令的執行。
我正在暫存一個生產數據庫,並且我的
pg_largeobject
表膨脹到了整個持久性虛擬設備容量的 40%。如何在執行 PostgreSQL 數據庫的 RDS 實例上執行(在此處
vacuumlo
的其他 DBA.SE 問題中有很好的解釋)?
在此處(在官方 PostgreSQL 儲存庫的 GitHub 鏡像中)找到
vacuumlo
我當時正在使用的 PostgreSQL 數據庫版本的來源。你可以想像剩下的:我只是模仿程序正在執行的操作,這裡也簡單描述。
1.臨時建表。
準備對象引用或 OID 的臨時表。
1.1。臨時 lob 表作為完整 lob 表的副本。
=> SET search_path = pg_catalog; [...] => CREATE TABLE vacuum_lo_removeme AS \ SELECT oid AS lo FROM pg_largeobject_metadata; [...] => ANALYZE vacuum_lo_removeme; [...] => _
1.2. 限制臨時 lob 表。
執行查詢,返回所有鍵入 OID 的數據庫列:
=> SELECT s.nspname, c.relname, a.attname FROM pg_class c, pg_attribute a , pg_namespace s, pg_type t WHERE a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid AND a.atttypid = t.oid AND c.relnamespace = s.oid AND t.typname in ('oid', 'lo') AND c.relkind in ('r','m') AND s.nspname !~ '^pg_';
接下來,您必須對先前查詢獲取的所有結果執行此查詢(注意
${VARIABLE}
,您應該根據自己的里程來替換),以便從臨時表中刪除實際使用的對象的所有 OID:=> DELETE FROM vacuum_lo_removeme WHERE \ lo IN (SELECT ${column} FROM ${SCHEMA}.${TABLE});
在我的情況下,它只有兩個表總共五列,實際上兩個表都是空的,所以這五個
DELETE
查詢自然沒有做任何事情。如果您有更大的啟用 OID 的子模式,您可能需要以某種方式自動執行此操作。
- 大對象取消連結。 ===========
最後,程序聲明了一個游標,該游標迭代
lo
臨時表的剩餘單元格,並通過lo_unlink
函式呼叫清除它們。2.A. 不要這樣做。
我應該使用 PLPGSQL 儲存過程來實現自動化,但由於我不擅長這類任務,所以我只發布了這個:
$ echo 'SELECT COUNT(*) FROM vacuum_lo_removeme;' | \ $MY_AUTOMATABLE_PSQL_MILEAGE count --------- 1117233 (1 row)
然後另一個迭代在孤立 OID 的臨時表中選擇第一個孤立 OID,然後取消連結並將其從表中刪除:
$ for i in {1..1117000}; do \ export oid=$(echo 'SELECT * FROM vacuum_lo_removeme LIMIT 1' | \ $MY_AUTOMATABLE_PSQL_MILEAGE | grep -v 'lo\|\-\-\-\-\|row\|^$' | \ sed s/\ //g) && \ echo "SELECT lo_unlink($oid); \ DELETE FROM vacuum_lo_removeme WHERE lo = $oid" | \ $MY_AUTOMATABLE_PSQL_MILEAGE; \ done lo_unlink ----------- 1 (1 row) DELETE 1 lo_unlink ----------- 1 (1 row) DELETE 1 lo_unlink ----------- 1 (1 row) DELETE 1 lo_unlink ----------- 1 (1 row) DELETE 1 ERROR: must be owner of large object 18448 DELETE 1 ERROR: must be owner of large object 18449 DELETE 1 ERROR: must be owner of large object 18450 DELETE 1 ERROR: must be owner of large object 18451 [...] lo_unlink ----------- 1 (1 row) DELETE 1 [...]
我知道它被優化得非常糟糕,但我讓它慢慢地刪除那些孤兒記錄。當根本不是 DBA 時,與使用一些有意義的慣用 PLPGSQL 相比,這些內襯更容易偽造。
但這太慢了,不能這樣。
2.B。比 2.A 做得更好(雖然還不是靈丹妙藥)。
您將能夠使用簡單的方法加速大型對象的取消連結,例如:
=> CREATE OR REPLACE FUNCTION unlink_orphan_los() RETURNS VOID AS $$ DECLARE iterator integer := 0; largeoid OID; myportal CURSOR FOR SELECT lo FROM vacuum_lo_removeme; BEGIN OPEN myportal; LOOP FETCH myportal INTO largeoid; EXIT WHEN NOT FOUND; PERFORM lo_unlink(largeoid); DELETE FROM vacuum_lo_removeme WHERE lo = largeoid; iterator := iterator + 1; RAISE NOTICE '(%) removed lo %?', iterator, largeoid; IF iterator = 100 THEN EXIT; END IF; END LOOP; END;$$LANGUAGE plpgsql;
注意不需要一次取消連結大型對象
100
,甚至不需要一次取消特定數量x
的對象,但一次取消連結100
是適用於所有 AWS 實例大小的預設記憶體配置的最安全基礎。如果為此使用過大的數字,則可能會因分配的記憶體不足而導致功能失敗;您如何做將取決於要取消連結的對像數量及其大小、實例類型和大小以及應用的手動進一步配置的程度。對於非 DBA 人來說,這有點容易偽造,然後用類似的東西呼叫它
$ for i in {0..$WHATEVER}; do echo 'SELECT unlink_orphan_los()' | \ $YOUR_AUTOMATABLE_PSQL_MILEAGE
根據臨時大對象的表大小和您的配置允許的每個事務的鎖數,構造常量在哪裡
${WHATEVER}
(我正在使用 RDS 預設值,但bash
我想我什至不必知道哪個是最大的)lo_unlink
RDBMS 允許使用 current的 s 數max_locks_per_transaction
。3.
VACUUM
大對象表。由postgres 郵件列表中的這個執行緒提示,我明白我應該
VACUUM
pg_largeobject
在取消連結對像後。我不確定其中哪些是最低要求集,或者執行它們的適當時間,但其中一些可能會有所幫助,並且不會造成任何損害:
VACUUM ANALYZE VERBOSE pg_largeobject_metadata; VACUUM ANALYZE VERBOSE pg_largeobject; VACUUM FULL ANALYZE VERBOSE pg_largeobject_metadata; VACUUM FULL ANALYZE VERBOSE pg_largeobject;
當微實例取消連結對象時,我執行了幾次(花費了非常長的時間,唉),首先當大約 1/4 的對像已經被取消連結,並且一些小儲存還給作業系統時,其次當大約 1/3 的對像已經取消連結,並且另外一些小儲存被歸還給作業系統時作業系統,第三,當大約 3/5 的對像已經被取消連結時,實例經歷了大量的儲存回饋給作業系統:我一直在尋找這種巨大的儲存回饋。執行官方首頁上的最大表查詢後,未連結的對象總數不到 3/4,對象表縮小到不到 3GiB,與最初的 20GiB 相差甚遠,甚至更臃腫。
注意對錶進行自動快速
VACUUM ANALYZE
迭代具有與執行單個VACUUM FULL
.