VACUUMの現状と展望(EDBチーフアーキテクト、Robert Hass)

EDB Postgres

Robert Haas Vice President, Chief Architect, Database Server at EnterpriseDB
Robert Haas, Vice President,
Chief Architect, Databese Server

この記事では、近年のVACUUMの改善の歴史、PostgreSQLにおけるVACUUMの現状、そして今後どのように改善されるのかを話したいと思います。

私が最初にPostgreSQLを使い始めた頃、オートバキュームは存在せず、手動のVACUUMを行う必要性も感じませんでした。しかし、数ヶ月過ぎた頃、なぜか私のデータベースがとても遅くなりました。 そこで、cronで6時間ごとにvacuumdbコマンドが実行されるようにスケジュールすることで対応しました。当時の私のニーズでは、そのレベル十分でした。データベースが小さく、限られた量のトラフィックしか処理しなかったからでしょう。

多くの環境では、UPDATEおよびDELETE操作が頻繁に行われるテーブルは、そうでないテーブルと比べて、不要行バージョンがかなりの速さで蓄積され、VACUUMとVACUUMの間隔も変化します。このような環境では、頻繁に更新されるテーブルのために、ユーザがフルデータベースのVACUUMの実行頻度を上げると、あまり更新されないテーブルまで必要以上に更新することになってしまい、無駄な労力がかかります。それを避けるために全データベースVACUUMの頻度を減らしてしまうと、頻繁に更新されるテーブルが、逆に、バキュームされずに、ディスク上のサイズは不要行バージョンで肥大化します。

PostgreSQL 8.3

PostgreSQL 8.3は、合理的な新しいオートバキュームを最初にリリースしました。はじめて、オートバキュームがデフォルトで有効になりました。また、マルチプロセスアーキテクチャを採用しているため、複数のテーブルを同時に自動的にバキュームすることができました。もちろん、オートバキュームはどのテーブルがバキュームされるべきかを把握し、バキュームを手動でスケジュールする必要がほとんどなくなりました。これは大きな前進でした。初めて、PostgreSQLのすべてのユーザがPostgreSQLを設定したときにVACUUMの設定を心配する必要がなくなったのです。

PostgreSQL 8.4

PostgreSQL 8.4にはさらに2つの大きな改良が加えられました。古いリリースでは、固定サイズのフリースペースマップがありました。このマップは、構成パラメータを変更してサーバーを再起動することによってのみサイズを変更できます。

データベース内の空き領域のページ数が、フリースペースマップの構成済みサイズを超えた場合、サーバーは空き領域を含む一部のページの追跡ができず、データベースの肥大化とつながっていました。 PostgreSQL 8.4では、空き領域の追跡を失うことのない、新しい動的なフリースペースマップが導入されました。

また、ビジビリティマップも追加されました。これにより、VACUUMは新しいVACUUMとの間にテーブルが変更されていない部分を再びスキャンすることをスキップすることができるようになりました。

ただし、毎回インデックスの全体をスキャンする必要がありました。トランザクションIDのラップアラウンドを防ぐために、テーブル全体を定期的にスキャンする必要があったからです。トランザクションIDラップアラウンドを防止する目的のためのVACUUMは、通常のVACUUMに比べてまれです。テーブル内のデッドタプルの数が推定テーブル数の500 + 20%を超えると、前者がデフォルトでトリガーされます。いずれの場合も、これらの値は構成パラメータを調整することによって変更できます。

PostgreSQL 8.4以降

PostgreSQL 8.4以降のいくつかの改善点は、VACUUMがスタックしないようにすることにフォーカスしています。さまざまな状況における基本的な問題点は、オートバキュームプロセスが何らかのロックで、長時間実行できない状況となった場合、(1) VACUUMプロセスは、一時点で一つのテーブルしか処理できないため、テーブルがバキュームされない (2) システム内の他のテーブルでVACUUMを実行できるオートバキュームワーカーが1つ少なくなり、他のテーブルを即座にバキュームできない。といったもので、どちらの問題も肥大化を招く可能性があります。

PostgreSQL 9.1では、オートバキュームワーカーにバキューム処理の対象となっていたテーブルをスキップするよう教えることで少し改善されましたが、すぐにリレーションロックを取得することはできませんでした。オートバキュームは毎分再試行されるので、問題はありませんが。

PostgreSQL 9.2では、ブロックが削除または固定されている必要があるタプルが含まれていて、トランザクションIDがラップアラウンドしないようにする目的を除いて、システムがクリーンアップロックをすぐに取得できない個々のテーブルブロックをスキップするように改良されました。

PostgreSQL 9.5では、B-Treeインデックススキャンで最後にアクセスされたインデックスページのピンが保持されるケースが減少しました。これにより、VACUUMがインデックススキャンを待たずにすみます。このような改善点を見れば、インデックススキャンの問題は完全には解決されていませんが、問題を着実に摘み取りつつあります。

その他の改善点

VACUUMが各ヒープページをスキャンする回数を減らすことを目的とした、いくつかの改善点もあります。 PostgreSQL 9.3以前では、VACUUMとVACUUMの間で変更されていないテーブルページは、2番目のVACUUMですべて表示され、トランザクションIDラップアラウンドを防ぐためにトリガーされたものを除いて、将来のVACUUMではスキップされます。

PostgreSQL 9.6では、トランザクションIDのラップアラウンドを防ぐためにトリガーされたVACUUM中でもページをスキップすることが可能になりました。これを実現するために、ビジビリティマップをさらに改善して、ページがすべて可視であるかどうか(つまり、不定期の行バージョンを含まないかどうか)だけでなく、すべてがフリーズしているかどうか(つまり、最終的なトランザクションIDラップアラウンドのリスクのあるタプルを含まないかどうか)も確認できます。後者のカテゴリーのページは無条件にスキップできます。VACUUMにとって意味が無いからです。

上記に加えて、長年に渡ってロギングの改善と他のいくつかの効率の改善が行われています。

インデックススキャンの課題

PostgreSQL開発コミュニティは、VACUUMが不要なテーブル・スキャンを実行するのを大幅に改善しましたが、基本的にインデックス・ページの不要なスキャンを避けることはできていません。たとえば、不要行バージョンを検出しないVACUUMであっても、B-Treeインデックスをスキャンして空のページをリサイクルします。これを改善するための努力が進められていますが、B-TreeインデックスがトランザクションIDのラップアラウンドとどのように相互作用するかの詳細で悩んでいます。

あまり多くない不要行バージョンが存在する場合の動作を改善することも求められています。 1TBテーブルに10個の不要行バージョンが含まれている場合、特にそれらがすべて同じページにある場合は、これらの行バージョンのインデックスポインターを削除するために、全てのインデックスをスキャンするのでは意味がありません。しかし、不要行バージョンがわずかしかない場合、オートバキュームが一般に最初にトリガーされないということで、この問題はそれほど気になりません。

バルクオペレーションの利点

VACUUMはバルクオペレーションのままです。いくつかの点で、これは良いことです。なぜなら、多数の関連する操作をまとめて1つの操作にまとめると、それらを1つずつ実行するより効率的になるからです。しかし、VACUUMが稼動しているとき、特に実行されていない長い時間が経過した後でも、リソースの使用率は驚くようなものになり、大きなテーブルではそれが長時間持続する可能性があります。大きなテーブルのVACUUMを一連の小さなステップに分割できるかどうかについて考える必要があるようです。

コストベースVACUUM遅延の課題

コストベースVACUUM遅延のデフォルト設定は、大規模なデータベースでは小さすぎます。デフォルトでは、オートバキュームは20msのコスト遅延で実行され、vacuum_cost_limit、vacuum_cost_page_dirty、およびvacuum_cost_page_missのデフォルト設定では、クリーニングを必要としないテーブルまたはインデックスページをスキャンする場合はVACUUMを約28.8GB /時間に、スキャンを行う場合は約9.6GB /時間テーブルまたはインデックスページのすべてをクリーニングする必要があります。数百ギガバイトまたはテラバイトのサイズのテーブルの場合、これはVACUUMの処理時間が長くなりすぎる危険があります。VACUUMが完了する前にテーブルが再び空になってしまうと、テーブルが肥大化します。

調整能力の課題

また、VACUUMは、システムビジーおよびアイドル期間に基づいてアクティビティを調整する能力がありません。なぜなら、これらの期間がいつ発生するか分からないからです。理想的には、アイドル中は最大速度でのバキュームを実行し、システムが多重負荷の状態になると、ゆっくりと進んで欲しいところです。しかし、このようなコントロールができるスケジューリングシステムはありません。このタイプの動作が必要な場合は、手動で構成する必要があります。

要約

上記のすべてをひとことで要約すると、「VACUUMは長い道のりを歩んできましたが、まだ監視と管理が必要である」と言えるかもしれません。私が使用した初期の頃のような小規模なインストールは、現在のバージョンのPostgreSQLを実行すると、VACUUMについてまったく何もする必要がなく、大規模なインストールでも、以前のリリースよりもほとんど問題が発生しません。同時に、常に安定した性能が要求される大規模なインストールでは、VACUUMは通常、少なくとも監視、管理、調整を必要とします。将来のリリースでどのような改善がもたらされるかは、時間が来ればわかるでしょう。

Robert Hassは、EnterpriseDBデータベースサーバー担当副社長兼チーフアーキテクトです。この記事はロバートの個人ブログからの転載です。

[出典:米国EDB公式ホームページ]


▼ 出典URL
https://www.enterprisedb.com/blog/state-vacuum