データベースの性能向上や安定運用には適切なメモリ設定が必要である。ディスクアクセスはメモリアクセスに比べ極めて遅く、可能な限りメモリから読み書きすることで応答性能を向上させたい一方、過度なメモリ割り当てはOOM(Out Of Memory、メモリ不足によるプロセス強制終了)リスクを高め、システム全体の停止につながる可能性がある。したがって、安定性を担保しつつ性能を確保するために、PostgreSQLのメモリ管理設定を慎重に行う必要がある。
本稿では、PostgreSQL公式ドキュメントや実運用の知見、Gihyo記事などを踏まえ、共有メモリ域とローカルメモリ領域の基本構成から主要パラメータの設定指針、運用上の検証手順までをまとめる。
PostgreSQLはマルチプロセスモデルを採用しており、サーバ起動時に生成されるマスタプロセス、WAL書き込みなどを担うバックグラウンドプロセス群、クライアント接続ごとに生成されるバックエンドプロセス(セッションプロセス)から構成される。各プロセスは独自にメモリを使用し、特に接続数に比例して増加するバックエンドプロセスのメモリ割り当てが全体のメモリ消費に大きく影響する。
メモリ管理は大きく以下の2つに分かれる。
shared_buffers、wal_buffers、Free Space MapやVisibility Mapなどがある。work_mem、maintenance_work_mem、temp_buffersなどが該当し、動的にSET可能なものもある。shared_buffersはPostgreSQLがデータベースキャッシュとして使用する共有メモリの量を設定するパラメータである。デフォルト128MBは小さいため、専用サーバであればシステムメモリの約25%を初期値とし、OSキャッシュとのバランスを見ながら段階的に増加を試みる。
shared_buffers = '2GB'など明示的に単位付きで指定することが推奨される。shmmaxやTransparent Huge Pages無効化、NUMA最適化が必要な場合がある。shared_buffers増加に伴いmax_wal_sizeやcheckpoint_completion_targetの調整が必要。これによりチェックポイント時のwrite burstやI/Oスパイクを緩和できる。work_memは並び替え、ハッシュ結合などの一時操作で使用可能な上限メモリを設定する。各クエリ実行プロセス、かつ各操作ごとに上限が適用されるため、実際の消費量はwork_mem × 一時操作数 × パラレルワーカー数 × 同時セッション数といった要素に依存する。最悪の場合には大きなメモリ消費に至る可能性がある。ただしこれは理論上の最大想定であり、実際のクエリ内容やタイミングにより変動するため、あくまで目安として捉えるべきである。
work_mem = '16MB'などと明示指定。max_parallel_workers_per_gatherと連動して消費量が増加する。hash_mem_multiplierによりハッシュ操作のメモリ利用上限が制御される。effective_cache_size: プランナが使用可能と想定するキャッシュ量(実メモリ消費には直接影響しない)が、インデックス利用判断に大きく影響する。maintenance_work_mem: VACUUMやインデックス作成時の作業メモリ。temp_buffers: 一時テーブル用メモリ領域。max_connectionsとPgBouncer: 同時接続制御でメモリ消費を抑制。max_parallel_workers_per_gather: パラレルクエリのワーカー数制御。replication_slot_max_wal_size: レプリケーションスロットが保持できる最大WALサイズ。autovacuum_work_mem: 自動バキュームプロセスが使用するメモリ。デフォルトはmaintenance_work_memの値。logical_decoding_work_mem: 論理デコード時のメモリ使用上限(PostgreSQL 13以降)。wal_buffers: WAL書き込み用のバッファ。自動設定されるが、高負荷時には調整が効果的。temp_file_limit: セッションが利用可能な一時ファイルのサイズ上限(MB単位)。bgwriter_lru_maxpages, bgwriter_lru_multiplier: バックグラウンドライタのバッファ書き出し量と頻度制御。shared_memory_type: mmap/sysv/windows のどの方式で共有メモリを確保するか。huge_pages: OSのHuge Pages(Transparent Huge Pages)使用有無。PostgreSQLのメモリ管理はshared_buffersとwork_memを中心に、プロセスごとの消費や同時接続数、パラレルクエリ特性を加味した総合設計が不可欠である。設定変更は段階的に行い、事前検証・リスク評価・継続監視の3点を徹底することで、安定性と性能を両立した運用を実現できる。
関連書籍