Postgresql

我可以對 pg_largeobject 表執行 VACUUM FULL 嗎?

  • August 19, 2021

我在 Postgres 9.1 數據庫中有兩個表 ( table1, )。table2兩者都有oid類型。每張表100萬條記錄。pg_largeobject表大小約為 40GB 。我從每個表中刪除了 90 萬條記錄,並執行了以下命令。

vacuum full analyze table1;
vacuum full analyze table2;

表大小仍然沒有變化pg_largeobject(啟用自動真空)

我是否也需要執行上述命令到pg_largeobject表格?它會影響什麼嗎?

可以執行它,沒問題:

VACUUM FULL ANALYZE pg_largeobject;

甚至可能刪除一些死行。細節:

但這可能不會解決您的實際問題

當使用Postgres的大對象工具時,大對象(“blob”:二進制大對象)本身被分解成儲存在系統表中的二進制數據塊pg_largeobject。PK 由兩列組成,(loid, pageno)用於引用使用者表中的 blob。OID可以多次引用同一個 blob 。loid``oid

刪除使用者表中的行不會刪除 blob。一方面,同一個 blob 可能被多次引用。您有責任自己跟踪並實際刪除“未連結”的 blob。一種方法是使用lo_unlink()

SELECT lo_unlink(173454);  -- deletes large object with OID 173454

由於您已經使用引用刪除了行,因此oid您需要更有創意來辨識未連結的 blob。假設您沒有從任何其他地方引用 blob,您可以使用此查詢來修復

SELECT lo_unlink(l.loid)
FROM   pg_largeobject l
GROUP  BY loid
HAVING (NOT EXISTS (SELECT 1 FROM table1 t WHERE t.oid = l.loid))
AND    (NOT EXISTS (SELECT 1 FROM table2 t WHERE t.oid = l.loid));

您需要成為超級使用者才能直接訪問pg_largeobjecttable1假設和中的列名table2oid。基於pg_largeobject_metadataPostgres 9.3 或更高版本的更簡單查詢(如@Daniel 評論):

SELECT lo_unlink(l.oid)
FROM   pg_largeobject_metadata l
WHERE (NOT EXISTS (SELECT 1 FROM table1 WHERE t.oid = l.oid))
AND   (NOT EXISTS (SELECT 1 FROM table2 WHERE t.oid = l.oid));

pg_largeobject_metadata是公開可讀的。但是我在 pg 9.3 之前的版本(包括 pg 9.1)中沒有看到系統表中 blob 的 OID - 至少在手冊中沒有,我現在沒有舊版本要測試。所以你可能必須使用我的第一個查詢。

前後對比:

SELECT count(*) FROM pg_largeobject;
SELECT pg_size_pretty(pg_table_size('pg_largeobject'));

VACUUM FULL現在可以執行,然後再次測試:

VACUUM FULL ANALYZE pg_largeobject;

您將對Postgres 9.1 可用的附加模組感興趣。lo該手冊對您的問題有準確的描述:

…一個表條目可以通過 OID 引用一個大對象,但是可以有多個表條目引用同一個大對象 OID,因此系統不會因為您更改或刪除一個這樣的條目而刪除大對象。

大膽強調我的。該模組也提供了一個解決方案:

lo模組允許通過將觸發器附加到包含 LO 引用列的表來解決此問題。觸發器基本上只是 lo_unlink在您刪除或修改引用大對象的值時執行。

對於每個 blob在整個數據庫中僅引用一次的案例。


顯然也(就像@Daniel提到的那樣)vacuumlo

vacuumlo 是一個簡單的實用程序,它將從 PostgreSQL 數據庫中刪除任何“孤立的”大對象。

引用自:https://dba.stackexchange.com/questions/112637