pg_repack 拡張機能を使用して、テーブルやインデックスの膨張を抑制する
pg_repack
拡張機能を使用して、VACUUM FULL
の代わりとしてテーブルやインデックスの肥大化を取り除くことができます。このエクステンションは、RDS for PostgreSQL のバージョン 9.6.3 以降でサポートされています。pg_repack
拡張機能の詳細については、GitHub プロジェクトのドキュメント
VACUUM FULL
とは異なり、pg_repack
拡張機能では、次の場合にテーブルの再構築オペレーション中に短期間だけ排他的ロック (AccessExclusiveLock) が必要です。
-
ログテーブルの初回作成 – 次の例に示すように、データの初回コピー中に発生した変更を記録するログテーブルが作成されます。
postgres=>
\dt+ repack.log_* List of relations -[ RECORD 1 ]-+---------- Schema | repack Name | log_16490 Type | table Owner | postgres Persistence | permanent Access method | heap Size | 65 MB Description |
-
最終スワップアンドドロップフェーズ。
再構築オペレーションの残りの部分で必要なのは、元のテーブルから新しいテーブルに行をコピーするための ACCESS SHARE
ロックのみです。これにより、INSERT、UPDATE、DELETE オペレーションを通常どおりに進めることができます。
レコメンデーション
次の推奨事項は、pg_repack
拡張機能を使用してテーブルとインデックスの肥大化を取り除く場合に適用されます。
-
業務時間外または他のデータベースアクティビティのパフォーマンスへの影響を最小限に抑えるために、メンテナンスウィンドウで再パックを実行します。
-
再構築アクティビティ中にブロッキングセッションを注意深くモニタリングし、
pg_repack
をブロックする可能性のあるアクティビティが元のテーブルにないことを確認します。特に、元のテーブルで排他的ロックが必要なときは、最後のスワップアンドドロップフェーズ中にアクティビティがないことを確認します。詳細については、「クエリをブロックしているものの特定」を参照してください。 ブロッキングセッションが表示された場合は、慎重に検討した後、次のコマンドを使用してセッションを終了できます。これは、
pg_repack
の継続によって再構築を完了するのに役立ちます。SELECT pg_terminate_backend(
pid
); -
トランザクション率が非常に高いシステムで
pg_repack's
ログテーブルから蓄積された変更を適用すると、適用プロセスが変更の速度に対して遅れる可能性があります。このような場合、pg_repack
は適用プロセスを完了できません。詳細については、「再パック中の新しいテーブルのモニタリング」を参照してください。インデックスが著しく肥大化している場合、代替の解決策は、インデックスのみの再パックを実行することです。これにより、VACUUM のインデックスクリーンアップサイクルをより速く完了させることもできます。PostgreSQL バージョン 12 の手動 VACUUM を使用してインデックスのクリーンアップフェーズをスキップできます。また、PostgreSQL バージョン 14 の緊急自動バキューム中は自動的にスキップされます。これにより、VACUUM はインデックスの肥大化を取り除くことなくより迅速に完了します。これは、循環 VACUUM の防止などの緊急時にのみ使用されます。詳細については、Amazon Aurora ユーザーガイドの「インデックスの肥大化の回避」を参照してください。
前提条件
-
テーブルには、PRIMARY KEY 制約または null 以外の UNIQUE 制約が必要です。
-
拡張機能のバージョンは、クライアントとサーバーの両方で同じである必要があります。
-
RDS インスタンスに、肥大化がないテーブルの合計サイズ以上の
FreeStorageSpace
があることを確認します。例として、TOAST とインデックスを含むテーブルの合計サイズが 2TB で、テーブルの肥大化の合計が 1TB であるとします。必須のFreeStorageSpace
は、次の計算によって返される値よりも大きくなければなりません。2TB (Table size)
-1TB (Table bloat)
=1TB
次のクエリを使用してテーブルの合計サイズを確認し、
pgstattuple
を使用して肥大化を導き出すことができます。詳細については、Amazon Aurora ユーザーガイドの「テーブルとインデックスの肥大化の診断」を参照してください。SELECT pg_size_pretty(pg_total_relation_size('table_name')) AS total_table_size;
このスペースは、アクティビティの完了後に再利用されます。
-
RDS インスタンスに再パックオペレーションを処理するのに十分なコンピューティング容量と IO 容量があることを確認します。パフォーマンスのバランスを最適化するために、インスタンスクラスをスケールアップすることを検討してください。
pg_repack
拡張機能を使用するには
-
次のコマンドを実行して、RDS for PostgreSQL DB インスタンスに
pg_repack
エクステンションをインストールします。CREATE EXTENSION pg_repack;
-
次のコマンドを実行して、
pg_repack
によって作成されたテンポラリログテーブルへの書き込みアクセス権を付与します。ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT INSERT ON TABLES TO PUBLIC; ALTER DEFAULT PRIVILEGES IN SCHEMA repack GRANT USAGE, SELECT ON SEQUENCES TO PUBLIC;
-
pg_repack
クライアントユーティリティを使用してデータベースに接続します。rds_superuser
権限を持つアカウントを使用します。例として、rds_test
ロールにrds_superuser
権限があるとします。次の構文は、postgres
データベース内のすべてのテーブルインデックスを含む完全なテーブルに対してpg_repack
を実行します。pg_repack -h
db-instance-name
.111122223333.aws-region
.rds.amazonaws.com -Urds_test
-kpostgres
注記
-k オプションを使用して接続する必要があります。-a オプションはサポートされていません。
pg_repack
クライアントからのレスポンスにより、再パッケージされる DB インスタンスのテーブルに関する情報が提供されます。INFO: repacking table "pgbench_tellers" INFO: repacking table "pgbench_accounts" INFO: repacking table "pgbench_branches"
-
次の構文は、
postgres
データベース内のインデックスを含む単一のテーブルorders
を再パックします。pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U
rds_test
--tableorders
-kpostgres
次の構文では、
postgres
データベース内のorders
テーブルのインデックスのみを再パックします。pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U
rds_test
--tableorders
--only-indexes -kpostgres
再パック中の新しいテーブルのモニタリング
-
データベースのサイズは、再パックのスワップアンドドロップフェーズまで、テーブルの合計サイズから肥大化を引いた数だけ増加します。データベースサイズの増加率をモニタリングし、再パックの速度を計算して、最初のデータ転送の完了にかかる時間を概算で見積もることができます。
例えば、テーブルの合計サイズを 2TB、データベースのサイズを 4TB、テーブルの合計肥大化を 1TB とします。再パックオペレーションの最後に計算によって返されるデータベースの合計サイズ値は次のとおりです。
2TB (Table size)
+4 TB (Database size)
-1TB (Table bloat)
=5TB
再パックオペレーションの速度を概算で見積もるには、2 つの時点の間の増加率をバイト単位でサンプリングします。増加率が 1GB の場合、最初のテーブル構築オペレーションが完了するまでに 1000 分または 16.6 時間かかることがあります。最初のテーブル構築に加えて、
pg_repack
は蓄積された変更を適用する必要があります。所要時間は、進行中の変更と蓄積された変更の適用速度によって異なります。注記
pgstattuple
拡張機能を使用して、テーブルの肥大化を計算できます。詳細については、「pgstattuple」を参照してください。 -
再パックスキーマの下の
pg_repack's
ログテーブルの行数は、最初のロード後に新しいテーブルに適用される保留中の変更の量を表します。pg_stat_all_tables
のpg_repack's
ログテーブルをチェックして、新しいテーブルに適用される変更をモニタリングできます。pg_stat_all_tables.n_live_tup
は、新しいテーブルに適用される保留中のレコードの数を示します。詳細については、「pg_stat_all_tables」を参照してください。 postgres=>
SELECT relname,n_live_tup FROM pg_stat_all_tables WHERE schemaname = 'repack' AND relname ILIKE '%log%';
-[ RECORD 1 ]--------- relname | log_16490 n_live_tup | 2000000
-
pg_stat_statements
拡張機能を使用して、再パックオペレーションの各ステップにかかる時間を調べることができます。これは、本番環境で同じ再パックオペレーションを適用する準備に役立ちます。出力をさらに拡張するようにLIMIT
句を調整できます。postgres=>
SELECT SUBSTR(query, 1, 100) query, round((round(total_exec_time::numeric, 6) / 1000 / 60),4) total_exec_time_in_minutes FROM pg_stat_statements WHERE query ILIKE '%repack%' ORDER BY total_exec_time DESC LIMIT 5;
query | total_exec_time_in_minutes -----------------------------------------------------------------------+---------------------------- CREATE UNIQUE INDEX index_16493 ON repack.table_16490 USING btree (a) | 6.8627 INSERT INTO repack.table_16490 SELECT a FROM ONLY public.t1 | 6.4150 SELECT repack.repack_apply($1, $2, $3, $4, $5, $6) | 0.5395 SELECT repack.repack_drop($1, $2) | 0.0004 SELECT repack.repack_swap($1) | 0.0004 (5 rows)
再パックは完全にアウトオブプレースオペレーションであるため、元のテーブルは影響を受けず、元のテーブルの復元を必要とする予期しない課題は予想されません。再パックが予期せず失敗した場合は、エラーの原因を調べて解決する必要があります。
問題が解決したら、テーブルが存在するデータベースに pg_repack
拡張機能を削除して再作成し、pg_repack
ステップを再試行してください。さらに、コンピューティングリソースの可用性とテーブルの同時アクセシビリティは、再パックオペレーションをタイムリーに完了させる上で重要な役割を果たします。