web-dev-qa-db-ja.com

RDS PostgreSQLデータベースを「バキュームロ」する方法

お気づきかもしれませんが、サービス製品としてのフルマネージドデータベースとして、AWS Relational Data Base Service(RDS)はユーザーランドコマンドの実行を制限します。

本番データベースをステージングしていて、pg_largeobjectテーブルは、永続性仮想デバイスの全容量の40%に膨れ上がりました。

PostgreSQLデータベースを実行しているRDSインスタンスでvacuumlo(他のDBA.SEの質問 here で美しく説明されています)を実行するにはどうすればよいですか?

3
48347

すべてのクレジットは https://dba.stackexchange.com/a/174664/83878 ですが、私の場合はソリューションを簡略化できました。私の場合、スキーマは1つしかありません。また、最初のステートメントsearch_path = pg_catalogシステムカタログを変更する権限がないため、私の場合は機能しません。単一の命令だけで、リンク解除手順を大幅に簡略化することもできました。

  1. 一時テーブルを作成しますvacuum_lo_removeme

存在しない場合のテーブルの作成vacuum_lo_removeme AS SELECT oid AS lo FROM pg_catalog.pg_largeobject_metadata

注:これはデフォルトのスキーマで作成されます。

  1. OIDが使用されているすべてのテーブルと列の名前を検索します。
SELECT c.relname as tablename, a.attname as columnname 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_' AND relname != 'vacuum_lo_removeme'
  1. すべてのテーブルを反復処理し、まだ使用されているラージオブジェクトをtmpテーブルから削除します。
DELETE FROM vacuum_lo_removeme WHERE lo IN (SELECT ${columnname} FROM ${tablename}

例:ここでJava=を使用しています(rsは前のステートメントのResultSetです):

            while (rs.next()) {
                String tablename = rs.getString("tablename");
                String columnname = rs.getString("columnname");
                // remove OID which must be kept
                String removeUsedOids = String.format("DELETE FROM vacuum_lo_removeme WHERE lo IN (SELECT \"%s\" FROM \"%s\")",
                        columnname, tablename);
                stmt = connection.createStatement();
                stmt.executeUpdate(removeUsedOids);
            }
  1. 孤立したLOを削除する
SELECT count(lo_unlink(lo)) from vacuum_lo_removeme where lo in (select loid from pg_catalog.pg_largeobject)
  1. ドロップDB
DROP table vacuum_lo_removeme
0
k_o_