今回はPostgreSQLのメモリ管理について記載します。
PostgreSQLのメモリ構成
以下、PostgreSQLのメモリ構成を簡単に記載します。
バックエンドプロセスは接続要求があると起動するプロセスですが、各バックエンドプロセスごとに、temp_buffer
、work_mem
、maintenance_work_mem
などが確保されます。
共有メモリは各プロセスやデータベースが共通に利用するメモリ領域です。
今回は各メモリの特長や設定値の目安を記載します。
共有メモリ領域
共有メモリは大きく共有バッファ、WALバッファ、空き領域(Free Space Map)、可視性マップ(Visibility Map)に分かれます。
共有バッファ(shared_buffers)
共有バッファはいわゆるOracle Databaseで言うところのバッファキャッシュです。テーブルやIndexのデータそのものをこの領域にキャッシュして利用します。カーネルパラメータのshmmaxよりも小さい値で設定することが大原則ですが、一般的にサーバに搭載されているメモリの25%程度で設定することが推奨値となります。大きければ大きいほど性能が出るといわれていますが、OSに必要なメモリ、他のプログラムで利用するメモリの事も勘案し、最大でも50%程度を目安に設定することが一般的となります。WALバッファ(wal_buffers)
これはトランザクションログをキャッシュする領域ですが、デフォルト値はshared_bufferの1/32で設定されるようになっています。小さくし過ぎると、頻繁にI/Oが発生してしまい、一方で大きくし過ぎると、リカバリー時間が長くなるデメリットがります。WALバッファの設定値は16MB~32MB程度で設定してみるのが一般的です。空き領域マップ(Free Space Map)
FreeSpaceMAPはOracleユーザーでは聞きなれない領域かもしれません。この領域ではテーブル上の利用可能な領域を管理しています。トランザクションから全く参照されていない行を探し、空き領域として再利用可能にしますが、その領域を管理しています。なので、このサイズが小さいと、空き領域を再利用することができず、クラスタのサイズが大きくなってしまうので調整が必要です。
設定値の目安はここに記載している通り、テーブルとインデックスの最大数をmax_fsm_relationに指定し、それに16をかけた値をmax_fsm_pagesに指定するという流れになります。
実際にFSMが不足しているとvacuumで警告が発生しますが、その例を記載します。
余談ですが、FSMはPostgreSQL11から機能改善されています。FSMの更新はバキュームの完了後に実施していました。このため、バキュームが完了できなかった場合、ガンガンPostgreSQLが肥大化する問題が発生していましたが、11からバキューム実行中でもFSMを更新するようになり、例えばテーブルでは8GBのバキュームが完了する度に、FSMを更新するようになりました。可視性マップ(Visibility Map)
最後が可視性マップです。テーブルのデータが可視であるか否かを管理する領域です。
VACUUMの処理の際にも高速化するために利用されます。これは実際に物理ファイルとしてテーブル単位で自動で作られますが、これをメモリ上で展開して参照などを行う事になります。PostgreSQL9.2以降ではインデックスオンリースキャン検索でも使用されます。
プロセスメモリ
プロセスメモリはプロセスごとに生成されるメモリ領域となります。大きく「作業メモリ」、「tempバッファ」で構成されメモリを確保したプロセスのみが参照可能です。
作業メモリ(work_mem)
クエリ実行時に行われる、並び替えやハッシュテーブル操作のために使われる領域となります。JOINやHASHテーブル操作が1つのSQLで複数回実行される場合、その数分だけ領域が確保されます。
以下の方法にて最大サイズの見積もりが可能です。
最大見積サイズ = (サーバの搭載メモリ – (shared_buffer + その他メモリ(OS、MW等)) /max_connections
また、初期設定値としては経験上、サーバの搭載メモリをmax_connectionsで割って、さらにその値を4や16で割った数を見積もりサイズとすることが多いです。
見積サイズ = サーバ搭載メモリ/max_connections/[4-16]メンテナンス用作業メモリ(maintenance_work_mem)
VACUUMやインデックス作成、外部キーの追加など、いわゆるデータベースメンテナンス操作で使用する領域となります。目安としてはサーバ搭載メモリの10%程度で最大でも1GB程度を設定することが推奨されていますが、VACUUMに問題がある場合には、この推奨値を超えてさらに大きくすることが必要な場合もあります。一時バッファ(temp_buffers)
Create temp table文で作成するテーブルを格納するためのメモリ領域となります。なので作成する一時テーブルの大きさに応じて調整することが望ましいという事になります。
最後に
Oracleと似たようなメモリ領域や、Oracleは更新型、PostgreSQLは追記型なので、その違いによってOracleには存在しないようなメモリ領域があることを、ご理解いただけたのではないかと思っております。
次回は
次回PostgreSQLで管理されるディレクトリやファイル関連について記載します。