-
2024-03-20 PostgreSQL
VACUUM と ANALYZE で収集される統計情報
PostgreSQL 16 で VACUUM に SKIP_DATABASE_STATS オプションと ONLY_DATABASE_STATS オプションが追加されました。
この 2 つのオプションについての説明を英語の公式ドキュメントから引用します。
【 PostgreSQL Documentation 16 - VACUUM - 】
https://www.postgresql.org/docs/current/sql-vacuum.html
SKIP_DATABASE_STATS
Specifies that VACUUM should skip updating the database-wide statistics about oldest unfrozen XIDs.
ONLY_DATABASE_STATS
Specifies that VACUUM should do nothing except update the database-wide statistics about oldest unfrozen XIDs.
簡単に言いますと
- SKIP_DATABASE_STATS は「VACUUM 時に『最も古い未凍結 XID に関するデータベース全体の統計情報』の更新は行わない」
- ONLY_DATABASE_STATSは「VACUUM 時に『最も古い未凍結 XID に関するデータベース全体の統計情報』の更新のみを行う」
というオプションになっています。
本記事では、この SKIP_DATABASE_STATS オプションを有効にした場合の挙動について、確認した結果を記載いたします。
ソースコードの確認
早速、この SKIP_DATABASE_STATS オプションを有効にした場合に、更新されなくなる統計情報が何かを確認します。
ソースコードでは src/backend/commands/vacuum.c が該当します。
この vacuum.c に vacuum 関数があり、その末尾で SKIP_DATABASE_STATS オプションを判定して処理を行なっています。
該当コードを下記に引用します。
if ((params->options & VACOPT_VACUUM) &&
!(params->options & VACOPT_SKIP_DATABASE_STATS))
{
/*
* Update pg_database.datfrozenxid, and truncate pg_xact if possible.
*/
vac_update_datfrozenxid();
}
vac_update_datfrozenxid 関数を呼び出しているコードのコメントに答えが書いてありました。
Update pg_database.datfrozenxid, and truncate pg_xact if possible.
pg_database の datfrozenxid を更新するのと、pg_xact を可能であれば truncate するとのことです。
SKIP_DATABASE_STATS オプションを有効にした VACUUM では、「pg_database.datfrozenxid の更新」と「(可能であれば)pg_xact の truncate」が行われなくなります。
そして ONLY_DATABASE_STATS オプションを有効にした VACUUM では、「pg_database.datfrozenxid の更新」と「(可能であれば)pg_xact の truncate」のみ行われます。
pg_database.datfrozenxid の更新
pg_database.datfrozenxid について、公式ドキュメントの説明を引用します。
【 PostgreSQL 15.4文書 - 53.15. pg_database - 】
https://www.postgresql.jp/document/15/html/catalog-pg-database.html
このデータベースの中で、この値よりも前のトランザクションIDは、永続的な(「凍結された」)トランザクションIDを持つように変更されています。 これは、このデータベースに対して、トランザクションID周回を防ぎ、かつ、pg_xactを縮小させることを目的としたバキュームを行うかどうかを追跡するために使用されます。 これはテーブル毎のpg_class.relfrozenxid値の最小値になります。
最後の説明文の「これはテーブル毎のpg_class.relfrozenxid値の最小値になります。」というのがポイントのようです。
VACUUM 時にすべてのテーブルの pg_class.relfrozenxid を確認し、その最小となる値を pg_database.datfrozenxid に格納するのですが、SKIP_DATABASE_STATS オプションを有効とすることで、pg_database.datfrozenxid の更新をスキップできます。
SKIP_DATABASE_STATS オプションを有効にするケース
pg_database.datfrozenxid の更新をスキップすることで、それだけ VACUUM が高速に完了します。
例えば、バッチ処理などで短期間に複数回 VACUUM を実行する場合、VACUUM の度に pg_database.datfrozenxid を更新しても、最終的には最後に実行された VACUUM で値が上書きされます。
そういった場合には、SKIP_DATABASE_STATS オプションを有効にして VACUUM を行い、最後に ONLY_DATABASE_STATS オプションを有効にした VACUUM を実行することで、全体的な VACUUM の処理時間を短縮できます。
VACUUM 時に更新される統計情報とは
補足情報ですが、VACUUM 時に更新される統計情報についても確認します。
PostgreSQL では、一口に統計情報といっても稼働統計情報とテーブル統計情報がありますが、VACUUM 時に更新される統計情報はテーブル統計情報となります。また、pg_class に関連する情報も VACUUM 時に更新されます。
公式ドキュメントを確認する
公式ドキュメントの中で、この VACUUM 時に更新される統計情報を説明している箇所を探しましたところ、VACUUM の「出力」にそれらしい説明がありました。
【 PostgreSQL 15.4 文書 - VACUUM - 】
https://www.postgresql.jp/document/15/html/sql-vacuum.html#id-1.9.3.184.7
VERBOSEが指定された場合、VACUUMは、現在処理中のテーブルを示す進行状況メッセージを表示します。 同様に、テーブルについての各種の統計情報も表示されます。
テーブルについての各種の統計情報、というのは pg_class のことを指しているようです。
ソースコードを確認する
次にソースコード上で、どうなっているのかを確認します。
src/backend/commands/vacuum.c を確認しますと、「vac_update_relstats」という統計情報の更新を行なっていそうな関数を見つけました。
そのコメントでは
Update the whole-relation statistics that are kept in its pg_class row.
とあり、やはり pg_class の内容を更新していることが説明されています。
統計情報を更新するコード
この vacuum.c の vac_update_relstats 関数の中で、pg_class の下記の項目を更新しています。
- relpages
- reltuples
- relallvisible
- relhasindex
- relhasrules
- relhastriggers
- relfrozenxid
- relminmxid
となっています。
実際に統計情報を更新しているソースコードを(すべてを引用するには長いので)一部引用します。
/* Apply statistical updates, if any, to copied tuple */
dirty = false;
if (pgcform->relpages != (int32) num_pages)
{
pgcform->relpages = (int32) num_pages;
dirty = true;
}
if (pgcform->reltuples != (float4) num_tuples)
{
pgcform->reltuples = (float4) num_tuples;
dirty = true;
}
if (pgcform->relallvisible != (int32) num_all_visible_pages)
{
pgcform->relallvisible = (int32) num_all_visible_pages;
dirty = true;
}
まとめ
以上が、SKIP_DATABASE_STATS および ONLY_DATABASE_STATS オプションについての確認となります。
データベースが大きくなればなるほど VACUUM 処理にかかる時間も増えますので、VACUUM 処理の時間を短縮したい場合には、この 2 つのオプションを使えるかどうかを検討するのが推奨となります。