pg_repack 拡張機能を使用して、テーブルやインデックスの膨張を抑制する - Amazon Relational Database Service

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 拡張機能を使用するには
  1. 次のコマンドを実行して、RDS for PostgreSQL DB インスタンスに pg_repack エクステンションをインストールします。

    CREATE EXTENSION pg_repack;
  2. 次のコマンドを実行して、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;
  3. pg_repack クライアントユーティリティを使用してデータベースに接続します。rds_superuser 権限を持つアカウントを使用します。例として、rds_test ロールに rds_superuser 権限があるとします。次の構文は、postgres データベース内のすべてのテーブルインデックスを含む完全なテーブルに対して pg_repack を実行します。

    pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test -k postgres
    注記

    -k オプションを使用して接続する必要があります。-a オプションはサポートされていません。

    pg_repack クライアントからのレスポンスにより、再パッケージされる DB インスタンスのテーブルに関する情報が提供されます。

    INFO: repacking table "pgbench_tellers" INFO: repacking table "pgbench_accounts" INFO: repacking table "pgbench_branches"
  4. 次の構文は、postgres データベース内のインデックスを含む単一のテーブル orders を再パックします。

    pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders -k postgres

    次の構文では、postgres データベース内の orders テーブルのインデックスのみを再パックします。

    pg_repack -h db-instance-name.111122223333.aws-region.rds.amazonaws.com -U rds_test --table orders --only-indexes -k postgres

再パック中の新しいテーブルのモニタリング

  • データベースのサイズは、再パックのスワップアンドドロップフェーズまで、テーブルの合計サイズから肥大化を引いた数だけ増加します。データベースサイズの増加率をモニタリングし、再パックの速度を計算して、最初のデータ転送の完了にかかる時間を概算で見積もることができます。

    例えば、テーブルの合計サイズを 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_tablespg_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 ステップを再試行してください。さらに、コンピューティングリソースの可用性とテーブルの同時アクセシビリティは、再パックオペレーションをタイムリーに完了させる上で重要な役割を果たします。