Postgresqlのバキューム処理

こんにちわ、田原です。

お客様対応でpostgresqlのバキューム処理について調査する機会があり、
まとめましたので、内容を紹介します。

なぜpostgresqlにバキューム処理が必要なのか

postgresqlには以下の点を解決するため、バキューム処理が実装されています。

PostgreSQLのMVCC(Multi-Version Concurrency Control)の影響

PostgreSQLは同時実行制御にMVCC(Multi-Version Concurrency Control)を使用しており、
これが「デッドタプル」を生成する原因となります。

  • UPDATE操作: 既存の行を物理的に更新せず、新しいバージョンの行を作成し、古い行を「デッド」としてマーク
  • DELETE操作: 行を物理的に削除せず、削除マークを付けるだけ
        
    この場合、デッド、削除マークの領域はそのままpostgresql管理として残っていて、
    OSに領域を返すということはありません。
    また、Insertやupdateを実行しても、その領域を再利用されることはなく、
    残り続けてしまいます。

上記の動作から以下の問題点があります。

パフォーマンスの劣化

  • テーブルサイズの肥大化により、スキャン時間が増加
  • インデックスも肥大化し、検索効率が低下
  • ディスク容量の無駄遣い

システムリソースの圧迫

  • 不要なディスクI/O増加
  • メモリ使用量の増加
  • バックアップ時間の延長

統計情報の最新化

データの変動があった場合、統計情報を最新化しないと適切な実行計画が立てられず、パフォーマンスが劣化する可能性が高くなります。
そのため、システムを解析して統計情報を最新化する必要があります。

バキューム処理の役割と種類

・データベースの不要領域
・統計情報の最新化

前述の課題を解決するため、バキューム処理が用意されており、実行する必要があります。
また、バキューム処理にも以下の種類がありますので、そちらを役割ごとに説明していきます。

バキューム処理 ---+--- 自動実行 --- 自動バキューム処理(AUTO VACUUM)
                  |
                  +--- 手動実行 --- VACUUM コマンド ---+--- 標準 VACUUM
                                                      |
                                                      +--- VACUUM FULL ※VACUUMコマンドのオプションの一つという扱い

データベースの不要領域の回収

バキューム処理は、デッドタプルとなっている領域を回収します。
※タプル   :データベースでは「レコード」のこと。
※デッドタプル:レコードから削除や更新されて非表示となったレコードのこと。

自動バキューム処理(AUTO VACUUM)

領域を回収し、再利用可能な状態に変更します。(デッドタプルにする)。
排他的ロックを取得しないため、テーブルへの通常の読み書き操作と並行して実行することが可能です。
しかし、余った領域は OS には(ほとんどの場合)返されず、同じテーブル内で再利用できるように保持されるだけとなります。
索引に対しても同様の効果があります。

自動バキューム処理の注意点

  • CREATE TEMP TABLE で作成された一時表に関しては処理の対象から外れる。
  • パーティション化テーブルに対して ANALYZE コマンドを発行しない。

標準 VACUUM

動作は「自動バキューム処理」と同じです。
※一般的に管理者は標準 VACUUM を使用してください。。

【コマンド例】vacuum <テーブル名>;

VACUUM FULL

テーブルの内容全体を新しいディスクファイルに領域を余すことなく書き換えて、
OS に未使用の領域を返します。
合わせて索引の再構築も実施されます。

以下の点に注意が必要です。
・実行速度がかなり低速。
・処理中のテーブルに対する「排他ロック」が必要。
※一般的に管理者は VACUUM FULL の使用を避けるべきです。
【コマンド例】vacuum full <テーブル名>;

統計情報の取得

より良い実行計画を作成するのに、テーブルに関する統計情報が必要です。
ANALYZE コマンドで統計情報を取得することができますが、バキューム処理も同様に取得が可能となっています。 

自動バキューム処理(AUTO VACUUM)

テーブルの内容が大きく変更されたときはいつでも自動的に ANALYZE コマンドを実施して、統計情報を取得します。
なお、パーティション化テーブルに対しては、ANALYZE コマンドを実施しません。

標準 VACUUM

VACUUM 単独では実施されません。
オプションの「ANALYZE」を付与する必要があります。
もちろん、このオプション付きで実施することで、「不要領域の回収」と「統計情報の取得」が行われます。

VACUUM FULL

意外と思いますが、VACUUM FULL だけでは実施されません。
オプションの「ANALYZE」と一緒に実行する必要があります。

 【コマンド例】vacuum full analyze <テーブル名>;

  • vacuum analyze full <テーブル名>; で実行するとエラーになります。
  • vacuum full analyze <テーブル名>; で実行すると、内部では vacuum full → analyze の順番で実施されています。(実行時を監視した結果より判断しています。)

VACUUM FULL と REINDEX の違い

VACUUM FULLとREINDEXの双方とも索引の再構築が実施されます。

索引の再構築中の出力例

postgres=> select * from pg_stat_progress_cluster;
-[ RECORD 1 ]-------+-----------------
pid                 | 2119
datid               | 5
datname             | postgres
relid               | 106524
command             | VACUUM FULL
phase               | rebuilding index ★
cluster_index_relid | 0
heap_tuples_scanned | 15436442
heap_tuples_written | 15436442
heap_blks_total     | 237483
heap_blks_scanned   | 237483
index_rebuild_count | 2

なお、VACUUM FULLとREINDEXコマンドでは目的や対象が異なります。
また、索引が破損した場合はVACUUM FULLでは対応できません。

■VACUUM FULL
目的:ディスクスペースの回収
対象:テーブルと索引
索引の破損:修復不可

■REINDEX
目的:索引の再作成
対象:索引
索引の破損:修復を試行

関連ビュー

pg_stat_all_tablesビュー

VACUUM と ANALYZE を実行したタイミングを確認できます。

select relname,last_vacuum,last_autovacuum,last_analyze,last_autoanalyze  from pg_stat_all_tables where relname=‘<テーブル名>’;

各列の説明

説明
last_vacuum テーブルが手作業で VACUUM された最終時刻 (VACUUM FULLは含まれない)
last_autovacuum AUTO VACUUM の影響によりによりテーブルが VACUUM された最終時刻
last_analyze 手動でテーブルを ANALYZE した最終時刻
last_autoanalyze AUTO VACUUM の影響により自動でテーブルを ANALYZE した最終時刻

pg_stat_progress_vacuumビュー

VACUUM の進捗状況を確認するビューです。
ただし、VACLUUM FULL に関しては pg_stat_progress_clusterビュー側で確認する必要があります。

phase 列の出力※マニュアル抜粋

フェーズ 説明
initializing VACUUMは、ヒープをスキャンし始める準備をしています。 このフェーズは、非常に短時間であると予想されます。
scanning heap VACUUMは、現在ヒープをスキャン中です。 必要であればそれぞれのページを切り取り、デフラグし、場合によってはフリーズ活動を実行します。 スキャンの進捗状況の監視にheap_blks_scanned列が使用できます。
vacuuming indexes VACUUMは、現在インデックスをバキューム処理中です。 テーブルにインデックスが存在する場合、ヒープが完全にスキャンされた後に、バキューム実行ごとに少なくとも1回発生します。maintenance_work_memが、発見された無効タプルの数量を格納するのに不十分な場合(または、自動バキュームの場合はautovacuum_work_memが設定されている場合)は、バキューム実行ごとに複数回発生する可能性があります。
vacuuming heap VACUUMは、現在ヒープをバキューム処理中です。 ヒープのバキュームは、ヒープのスキャンと異なり、インデックスをバキューム処理するそれぞれのインスタンスの後に発生します。heap_blks_scannedheap_blks_totalより少ない場合、システムはこのフェーズの完了後にヒープのスキャン処理に戻ります。 さもなければ、このフェーズの完了後にインデックスの整理を始めます。
cleaning up indexes VACUUMは、現在インデックスの整理処理中です。 これは、ヒープが完全にスキャンされ、インデックスとヒープが完全にすべてバキューム処理された後に発生します。
truncating heap VACUUMは、現在リレーションの終点の空のページをオペレーティングシステムに戻すためにヒープを切り詰めています。 これは、インデックスの整理処理後に発生します。
performing final cleanup VACUUMは最終クリーンアップを実行しています。 このフェーズ中に、VACUUMは空き領域マップをバキュームし、pg_class内の統計を更新し、累積統計システムに統計を報告します。 このフェーズが完了すると、VACUUMは終了します。

pg_stat_progress_clusterビュー

VACUUM FULL の進捗状況を確認するビューです。
ビューの名称から主に CLUSTER コマンド用ですが、VACUUM FULL は CLUSTER の一種のため、
このビューで進捗状況を確認します。

phase 列の出力※マニュアル抜粋

フェーズ 説明
initializing コマンドはヒープのスキャンを開始する準備をしています。 本フェーズはごく短時間になると予想されます。
seq scanning heap コマンドは現在、テーブルをシーケンシャルスキャンを使ってスキャンしています。
index scanning heap CLUSTERは現在、インデックススキャンを使ってテーブルをスキャンしています。
sorting tuples CLUSTERは現在、タプルをソートしています。
writing new heap CLUSTERが新しいヒープに書き込んでいます。
swapping relation files コマンドは現在、新たに構築したファイルを置き換えて設置しています。
rebuilding index コマンドは現在、インデックスを再構築しています。
performing final cleanup コマンドは現在、最終クリーンアップを実行中です。 このフェーズが完了すると、CLUSTERVACUUM FULLは終了します。

pg_stat_progress_analyzビュー

ANALYZE の進捗状況を確認するビューです。
VACUUM ANALYZE や VACUUM FULL ANALYZE のうち、ANALZYE フェーズはこちら側で進捗を確認する必要があります。

phase 列の出力※マニュアル抜粋

フェーズ 説明
initializing コマンドはヒープをスキャンし始める準備をしています。 このフェーズは非常に短時間であると予想されます。
acquiring sample rows コマンドはサンプル行を得るため、relidで指定されたテーブルを現在スキャンしています。
acquiring inherited sample rows コマンドはサンプル行を得るため、子テーブルを現在スキャンしています。 列child_tables_totalchild_tables_donecurrent_child_table_relidはこのフェーズの進捗情報を含みます。
computing statistics コマンドはテーブルスキャンの間に得られたサンプルから統計情報を計算しています。
computing extended statistics コマンドはテーブルスキャンの間に得られたサンプルから拡張統計情報を計算しています。
finalizing analyze コマンドはpg_classを更新しています。 このフェーズが完了すれば、ANALYZEは終わります。

最後に

vacuum処理は意外と奥が深く、postgresqlにはなくてはならないものだと感じました。

著者について

Oracleのサポートを15年やっていましたが、新たな挑戦としてpostgresqlの理解を深めようと日々奮闘中です。

田原謙一をフォローする

クラウドに強いによるエンジニアブログです。

SCSKでは、自社クラウドと3大メガクラウドの強みを活かし、ハイブリッドクラウド/マルチクラウドのソリューションを展開しています。業界の深い理解をもとに、お客様の業務要件に最適なアーキテクチャをご提案いたします。サービスサイトでは、お客様のDX推進をワンストップで支援するサービスの詳細や導入事例を紹介しています。

PostgreSQLプロダクト
シェアする
タイトルとURLをコピーしました