詳解 PostgreSQL[10/11対応]―現場で役立つ新機能と実践知識

第2章 PostgreSQLの内部構造―プロセスやメモリの流れ,特徴的な機能のしくみ

この記事を読むのに必要な時間:およそ 6 分

メモリの構造と役割

RDBMSで重要なポイントと言えばメモリです。メモリには大きく分けて,共有メモリとプロセスメモリの2種類があります。

共有メモリは,すべてのプロセスから参照/更新される共有領域です。共有メモリは,PostgreSQLの起動時にOS経由で確保されます。

プロセスメモリは,バックエンドプロセスごとに確保される作業用領域です。メモリ領域を確保したプロセスのみが参照/更新できます。

共有メモリ,プロセスメモリは,それぞれいくつかの領域に分かれており,それぞれpostgresql.confの該当項目で設定します。

共有メモリ

共有メモリは,次の4つの領域に分かれています。

共有バッファ─⁠─プロセスが共通で使う

共有バッファは,テーブルやインデックスのデータをキャッシュする領域です。共有バッファはバックエンドプロセスや自動VACUUMワーカが参照/更新し,ライタがチェックポイントのタイミングで取り出してディスクに書き込みを行います。参照の際も,共有バッファにデータがある場合は高速に処理できます。後述する可視性マップと空き領域マップは,共有バッファを利用します。

共有バッファは,shared_buffersの項目で値を設定できます。デフォルト値は32MBです。割り当てとしては総メモリの25%程度を最初の目安にするのがよいでしょう。

可視性マップ─⁠─データファイルの参照可否を管理する

可視性マップは,テーブルのデータが参照できるか否かを管理する情報を扱う領域です。VACUUMの際に処理対象のページか判断する際に利用され,VACUUMの手助けをしています。PostgreSQL 9.2以降では,高速な検索方式のINDEX ONLY SCANの際にも利用されます。可視性マップは,VACUUM処理や各更新処理の際に更新されます。

空き領域マップ─⁠─データファイルの再利用を管理する

空き領域マップは,テーブル上の利用可能な領域を指し示す情報を扱う領域です。VACUUM処理の際にまったく参照されていない行を探し,空き領域として再利用できる状態にします。そのあと,追加や更新時に空き領域マップを探索し,空き領域を再利用します。

WALバッファ─⁠─WALで使う

WALバッファは,どのような更新を行ったかの記録であるWALをキャッシュする領域です。

WALバッファは,wal_buffersの項目で値を設定できます。PostgreSQL 9.1以降では自動調整されるため,デフォルト値のままで問題ありません。

プロセスメモリ

プロセスメモリは,次の3つの領域に分かれています。また,プロセスからメモリを経由してデータファイルを更新する流れが図2となります。

図2 メモリの利用からデータファイルの更新までの流れ

図2 メモリの利用からデータファイルの更新までの流れ

作業メモリ─⁠─クエリ実行時の使う

作業メモリは,クエリの実行時にソートやハッシュテーブルの利用のために使われる領域です。

作業メモリは,work_memの項目で値を設定できます。大きなデータを扱うクエリが遅い場合,work_memの値を増やすと改善することがあります。ただし,work_memはバックエンドプロセスごとに確保されるため,work_memに大きな値を設定している場合に接続数が多いと,OSのメモリを圧迫することがあります。

また,サービス開始当初はwork_memの値が小さくても取り扱うデータも小さいため問題にならなかったものが,サービスの成長とともに取り扱うデータサイズが大きくなり,ソートの際にメモリからあふれることがあります。その際はスワップが発生するので,処理速度が突然遅くなります。

このようなことを防ぐため,work_memの値は適切にチューニングする必要がありますし,スワップを監視する必要があります。work_memの最大値は

(OSの実メモリ - shared_buffers) / max_connections

ですので,これを超えないように適切な値を設定しましょう。最初から大きな値を設定するよりも,最初は32MB程度を設定し,スワップを監視しながら適宜調整するのがよいです。もちろん,もっと小さな値から初めても問題ありません。

メンテナンス用作業メモリ─⁠─メンテナンス時に使う

メンテナンス用作業メモリは,VACUUM,インデックス作成,外部キー制約の追加などのデータベースに対するメンテナンス時に利用する領域です。

メンテナンス用作業メモリは,maintenance_work_memの項目で値を設定できます。たとえばサービスのメンテナンスやDB移行時などのメンテナンス作業でALTERを同時に複数回実行した際に,maintenance_work_memがデフォルトのままだと時間がかかることがあります。この作業でスワップが発生している場合は,maintenance_work_memを大きな値に変更すると改善します。ただし,値を大きくし過ぎるとOSのメモリを圧迫しますので,最初から大きい値を設定しないようにしましょう。

一時バッファ─⁠─一時テーブル領域の作成で使う

一時テーブルはCREATE TEMP TABLE文を実行すると作成されますが,その際に利用される領域が一時バッファです。

一時バッファは,temp_buffersの項目で値を設定できます。CREATE TEMP TABLE文を実行した際にスワップが発生するようであれば,値を増やしましょう。

PostgreSQLのファイルの役割

PostgreSQLのファイルの役割を知ることは,PostageSQL の特徴をつかむうえで重要です。PostgreSQLのファイルは,基本的にbaseとglobalディレクトリ配下に保存されます。それぞれのファイルはオブジェクト識別子(OID)という番号によって管理され,base/1/1247のようなファイル名のみで判断できない形で保存されています。ただし,後述するWALファイルは,pg_walディレクトリ配下に保存されます。

PostgreSQLのファイルの中で,次の4つが重要です。

データファイル─⁠─テーブルの保存場所

データファイルは,テーブルのデータの実体が保存されるファイルです。データファイルは複数の8,192バイトのページ(Oracle DBで言うところのブロック)によって構成されます。

インデックスファイル─⁠─インデックスの保存場所

インデックスファイルは,インデックス情報が保存されるファイルです。データファイルと同様に複数の8,192バイトのページによって構成されます。

WALファイル─⁠─WALの保存場所

WALファイルは,WALの保存先です。データベースの永続性の保証を行うために重要なファイルで,16MBの固定サイズで作成されます。

TOASTファイル─⁠─大きなデータの保存場所

前述したように通常1つのページは8,192バイトです。TOASTファイルは,その1/4の約2KBを超えるサイズの行データを圧縮,格納する場合に作成されます。

TOASTは,長大な行データを保存するためのしくみです。PostgreSQLは複数ページにまたがるタプル(行データ)を許しません。そのため,ページの最大値である8KBを超えるデータを保存できません。そこで,TOASTが圧縮したり,分割したりして別の場所に保存してくれるのです。

ただし,TOASTも最大値が決まっており,1GBまでです。そのため,TOASTが利用できる型,たとえばTEXT型を利用していた場合に保存できる最大サイズは1GBです。

著者プロフィール

曽根壮大(そねたけとも)

株式会社オミカレ副社長兼CTO。数々の業務システム,Webサービスなどの開発・運用を担当し,2017年に株式会社はてなでサービス監視サービス「Mackerel」のCRE(Customer Reliability Engineer)を経て現職。 コミュニティでは,Microsoft MVPをはじめ,日本PostgreSQLユーザ会の理事として勉強会の開催を担当し,各地で登壇している。 builderscon 2017,YAPC::Kansaiなどのイベントでベストスピーカーを受賞し,分かりやすく実践的な内容のトークに定評がある。 他に,岡山Python勉強会を主催し,オープンラボ備後にも所属。著書に『Software Design』誌で,データベースに関する連載「RDBアンチパターン」をまとめた『失敗から学ぶRDBの正しい歩き方』を執筆。

@soudai1025
はてなid:Soudai

著書