RDS for PostgreSQL でバキュームのパフォーマンスに関する問題を解決する - Amazon Relational Database Service

RDS for PostgreSQL でバキュームのパフォーマンスに関する問題を解決する

このセクションでは、バキュームのパフォーマンスの低下を招く要因と、それらの問題に対処する方法について説明します。

大規模なインデックスのバキューム処理

VACUUM は、初期化、ヒープスキャン、インデックスとヒープバキューム、インデックスクリーンアップ、ヒープ切り捨て、最終クリーンアップのシーケンシャルフェーズで動作します。ヒープスキャン中、プロセスはページを除外し、デフラグしてフリーズします。ヒープスキャンが完了すると、VACUUM はインデックスをクリーンアップし、空のページがオペレーティングシステムに返されて、空き領域マップのバキューム処理や統計の更新などの最終的なクリーンアップタスクを実行します。

maintenance_work_mem (または autovacuum_work_mem) がインデックスの処理に不十分な場合は、インデックスのバキューム処理に複数のパスが必要になることがあります。PostgreSQL 16 以前では、デッドタプル ID を保存するために 1 GB のメモリ制限があり、大きなインデックスでは、多くの場合複数のパスが必要となっていました。PostgreSQL 17 では、単一の割り当て配列を使用する代わりにメモリを動的に割り当てる TidStore が導入されています。これにより、1 GB の制約がなくなり、メモリをより効率的に使用でき、インデックスごとに複数のインデックススキャンを行う必要が軽減されます。

使用可能なメモリがインデックス処理全体を一度に処理できない場合、大きなインデックスには PostgreSQL 17 で複数のパスが必要になることがあります。通常、大きなインデックスには、複数のパスを必要とするデッドタプルが多く含まれます。

低速バキュームオペレーションの検出

postgres_get_av_diag() 関数は、メモリ不足が原因でバキューム操作の実行が遅いタイミングを検出できます。この関数の詳細については、「RDS for PostgreSQL に自動バキュームのモニタリングツールと診断ツールをインストールする」を参照してください。

この postgres_get_av_diag() 関数は、使用可能なメモリが 1 回のパスでインデックスのバキューム処理を完了するのに十分でない場合、次の通知を発行します。

rds_tools 1.8

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_work_mem is "XXX" and might not be sufficient. Consider increasing the setting, and if necessary, scaling up the Amazon RDS instance class for more memory. 
        Additionally, review the possibility of manual vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;).

rds_tools 1.9

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_work_mem is XX might not be sufficient. Consider increasing the setting to XXX, and if necessary, scaling up the RDS instance class for more 
        memory. The suggested value is an estimate based on the current number of dead tuples for the table being vacuumed, which might not fully reflect the latest state. Additionally, review the possibility of manual 
        vacuum with exclusion of indexes using (VACUUM (INDEX_CLEANUP FALSE, VERBOSE TRUE) table_name;). For more information, see 
        Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide
        .
注記

postgres_get_av_diag() 関数では、pg_stat_all_tables.n_dead_tup を使用してインデックスのバキューム処理に必要なメモリ量を推定します。

postgres_get_av_diag() 関数が、autovacuum_work_mem が不十分なために複数のインデックススキャンを必要とするスローバキュームオペレーションを特定すると、次のメッセージが生成されます。

NOTICE: Your vacuum is performing multiple index scans due to insufficient autovacuum_work_mem:XXX for index vacuuming. 
        For more information, see Working with PostgreSQL autovacuum in the Amazon Amazon RDS User Guide.

ガイダンス

手動 VACUUM FREEZE を使用して次の回避策を適用し、テーブルのフリーズにかかる時間を短縮できます。

バキューム処理のためのメモリを増やす

postgres_get_av_diag() 関数で提案されているように、インスタンスレベルで潜在的なメモリの制約に対応するために、autovacuum_work_mem パラメータを増やすことをお勧めします。autovacuum_work_mem は動的パラメータですが、新しいメモリ設定を有効にするには、自動バキュームデーモンがワーカーを再起動する必要があることに注意してください。これを行うには、以下の手順を使用します。

  1. 新しい設定が指定されていることを確認します。

  2. 自動バキュームを現在実行しているプロセスを終了します。

このアプローチにより、調整されたメモリ割り当てが新しい自動バキューム操作に適用されます。

より迅速な結果を得るには、セッション内で maintenance_work_mem 設定を増やし、手動で VACUUM FREEZE 操作を実行することを検討してください。

SET maintenance_work_mem TO '1GB'; VACUUM FREEZE VERBOSE table_name;

Amazon RDS を使用していて、maintenance_work_mem または autovacuum_work_mem のより高い値をサポートするために追加のメモリが必要であると判断した場合は、より多くのメモリを持つインスタンスクラスにアップグレードすることを検討してください。これにより、手動バキューム操作と自動バキューム操作の両方を強化するために必要なリソースが提供され、バキューム処理とデータベースの全体的なパフォーマンスが向上します。

INDEX_CLEANUP を無効にする

PostgreSQL バージョン 12 以降の手動 VACUUM ではインデックスのクリーンアップフェーズを省略できますが、PostgreSQL バージョン 14 以降の緊急自動バキュームでは、vacuum_failsafe_age パラメータに基づいてこのフェーズが自動的に行われます。

警告

インデックスのクリーンアップを省略すると、インデックスが肥大化し、クエリのパフォーマンスに悪影響を及ぼす可能性があります。これを軽減するには、メンテナンスウィンドウで、影響を受けるインデックスに対してインデックスの再作成またはバキューム処理を行うことを検討してください。

大きなインデックスの処理に関するその他のガイダンスについては、「大きなインデックスを使った autovacuum の管理 」のドキュメントを参照してください。

インデックスの並列バキューム処理

PostgreSQL 13 以降では、手動 VACUUM を使用して、各インデックスに 1 つのバキュームワーカープロセスを割り当て、デフォルトで複数のインデックスのバキューム処理とクリーンアップを並列して行うことができます。ただし、バキューム操作が並列実行の対象となるかどうかを PostgreSQL が判断するには、特定の基準を満たす必要があります。

  • 少なくとも 2 つのインデックスが必要です。

  • max_parallel_maintenance_workers パラメータを 2 以上に設定する必要があります。

  • インデックスサイズが min_parallel_index_scan_size の制限 (デフォルトは 512KB) を超えている必要があります。

Amazon RDS インスタンスで使用可能な vCPU の数とテーブルのインデックスの数に基づいて max_parallel_maintenance_workers 設定を調整し、バキューム処理のターンアラウンド時間を最適化できます。

詳細については、「Parallel vacuuming in Amazon RDS for PostgreSQL and Amazon Aurora PostgreSQL」を参照してください。

バキューム処理対象のテーブルまたはデータベースが多すぎる

PostgreSQL の「The Autovacuum Daemon」ドキュメントで説明されているように、自動バキュームデーモンは複数のプロセスで動作します。このプロセスには、システム内の各データベースの自動バキュームワーカープロセスを開始する、永続的な自動バキュームランチャーが含まれます。ランチャーは、データベースあたり約 autovacuum_naptime 秒ごとにこれらのワーカーを開始するようにスケジュールします。

N 個のデータベースでは、新しいワーカーはおおよそ [autovacuum_naptime/N 秒] ごとに開始されます。ただし、同時ワーカーの合計数は autovacuum_max_workers 設定によって制限されます。バキューム処理を必要とするデータベースまたはテーブルの数がこの制限を超えると、ワーカーが利用可能になり次第すぐに次のデータベースまたはテーブルが処理されます。

多数の大きなテーブルやデータベースで同時にバキューム処理が必要な場合、使用可能なすべての自動バキュームワーカーが長時間占有され、他のテーブルやデータベースのメンテナンスに遅延が生じる可能性があります。トランザクションレートが高い環境では、このボトルネックがすぐに増大し、Amazon RDS インスタンス内で循環バキュームの問題が発生する可能性があります。

postgres_get_av_diag() が多数のテーブルまたはデータベースを検出すると、次の推奨事項が提示されます。

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound and it might be slow.
NOTICE: The current setting of autovacuum_max_workers:3 might not be sufficient. Consider increasing the setting and, if necessary, consider scaling up the Amazon RDS instance class for more workers.

ガイダンス

autovacuum_max_workers を増やす

バキューム処理を迅速化するために、autovacuum_max_workers パラメータを調整して同時実行の自動バキュームワーカーを増やすことをお勧めします。パフォーマンスのボトルネックが続く場合は、Amazon RDS インスタンスをより多くの vCPU を持つクラスにスケールアップすることを検討してください。これにより、並列処理機能をさらに向上させることができます。

(循環を防ぐための) 積極的なバキューム処理が実行されている

PostgreSQL のデータベースの経過時間 (MaximumUsedTransactionIDs) は、(循環を防ぐための) 積極的なバキューム処理が正常に完了した場合にのみ減少します。このバキューム処理が終了するまで、トランザクションレートに応じて経過時間は増加し続けます。

postgres_get_av_diag() 関数が積極的なバキュームを検出すると、次の NOTICE を生成します。ただし、この出力は、バキュームが少なくとも 2 分間アクティブになった後にのみトリガーされます。

NOTICE: Your database is currently running aggressive vacuum to prevent wraparound, monitor autovacuum performance.

積極的なバキュームの詳細については、「When an aggressive vacuum is already running」を参照してください。

次のクエリを使用して、積極的なバキュームが進行中かどうかを確認できます。

SELECT a.xact_start AS start_time, v.datname "database", a.query, a.wait_event, v.pid, v.phase, v.relid::regclass, pg_size_pretty(pg_relation_size(v.relid)) AS heap_size, ( SELECT string_agg(pg_size_pretty(pg_relation_size(i.indexrelid)) || ':' || i.indexrelid::regclass || chr(10), ', ') FROM pg_index i WHERE i.indrelid = v.relid ) AS index_sizes, trunc(v.heap_blks_scanned * 100 / NULLIF(v.heap_blks_total, 0)) AS step1_scan_pct, v.index_vacuum_count || '/' || ( SELECT count(*) FROM pg_index i WHERE i.indrelid = v.relid ) AS step2_vacuum_indexes, trunc(v.heap_blks_vacuumed * 100 / NULLIF(v.heap_blks_total, 0)) AS step3_vacuum_pct, age(CURRENT_TIMESTAMP, a.xact_start) AS total_time_spent_sofar FROM pg_stat_activity a INNER JOIN pg_stat_progress_vacuum v ON v.pid = a.pid;

出力の query 列をチェックすることで、(循環を防ぐための) 積極的なバキュームであるかどうかを判断できます。「to prevent wraparound」という語句は、それが積極的なバキュームであることを示しています。

query | autovacuum: VACUUM public.t3 (to prevent wraparound)

例えば、トランザクション経過時間が 10 億の時点でブロック要因があり、同じトランザクション経過時間での循環を防ぐために積極的なバキューム処理を必要とするテーブルがあるとします。さらに、トランザクション経過時間が 7 億 5,000 万の時点で別のブロック要因もあります。トランザクション経過時間 10 億でのブロック要因をクリアしても、トランザクション経過時間はすぐに 7 億 5,000 万には低下しません。積極的なバキューム処理を必要とするテーブル、または経過時間が 7 億 5,000 万を超えるトランザクションが完了するまで、高いままとなります。この間、PostgreSQL クラスターのトランザクション経過時間は増加し続けます。バキューム処理が完了すると、トランザクションの経過時間は 7 億 5,000 万に低下しますが、さらにバキューム処理が完了するまで再び増加し始めます。このサイクルは、最終的にトランザクション経過時間が autovacuum_freeze_max_age で指定された Amazon RDS インスタンスの設定レベルに低下するまで、これらの条件が存続する限り続きます。