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

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

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

PostgreSQLの特徴的な機能のしくみ

ここからは,PostgreSQLの特徴的な機能のしくみを説明します。どれもPostageSQLを語るうえでは外せない機能ばかりです。

追記型アーキテクチャ─⁠─データ保存のしくみ

PostgreSQLがほかのデータベースと大きく違うところに,追記型アーキテクチャの採用があります。

追記型アーキテクチャとは,図3上部のUPDATE文のように,更新の際に直接データファイルは更新せず,参照を外して別のデータを挿入するアーキテクチャです。これにより,MVCCと呼ばれるロックの制御やトランザクションの制御がシンプルに実装されます。

図3 追記型とVACUUMのアーキテクチャ

図3 追記型とVACUUMのアーキテクチャ

もちろんデメリットもあります。たとえば,更新の際に参照を外す処理と挿入の処理の2つが必要なので処理速度が遅いのではないか,参照されなくなったファイルはどうするのか,などです。

以降では,これらを解決する機能を紹介します。

HOT─⁠─更新の性能向上のキーマン

更新の際に処理が遅い問題の解決として,HOTHeap Only Tupleがあります。HOTは更新の際にインデックスの更新量を大きく抑え,性能向上を行うしくみです。HOTについては,Let's Postgresの記事に詳しく書いてあります。このようにPostgreSQLは,追記型のメリットを活かしながらデメリットに対しても改善を行っています。

VACUUM─⁠─データファイルの掃除屋

追記型アーキテクチャによって参照されなくなったデータファイルを,再度データを挿入できるように再利用可能状態にする処理がVACUUMです。ガベージコレクションのような処理と言うとわかりやすいでしょうか。VACUUMについては,PostgreSQL Conference Japan 2018【T4】今,改めて学ぶVACUUM — 佐藤 友章の動画が参考になります。

VACUUMは,定期的に自動VACUUMランチャから自動VACUUMワーカが起動され,図3下部のとおり処理します。デフォルトで自動VACUUMが実行されるので,ユーザーがVACUUMを意識する必要はほとんどありません。ときどき,過去のPostgreSQLの知識でVACUUMによる性能遅延が激しいためVACUUMを停止するという話を見かけますが,これは現在では誤ったテクニックです。

VACUUMの注意点

ただし,ロングトランザクションやインデックスを更新するような処理をかなりの高頻度で行うような場合は自動VACUUMが実行されなかったり,逆に高頻度でVACUUMが実行されて性能遅延することがあります。これらの場合のみ,ユーザーが任意のタイミングで計画的に実行する必要があります。VACUUMの処理を十分に理解したうえで適切なスケジュールを組みましょう。

そのほかの注意点として,VACUUMは更新や削除によって生まれた参照されないデータを再利用可能にするだけですので,一度大きくなったデータファイルが小さくなることはありせん。たとえば大きなデータファイルの1,000万件のレコードを削除し,VACUUMが実行された場合,1,000万件分再利用できるようになるだけです。対象のデータファイルが1,000万件相当のデータ量分,小さくなるわけではありません。

データファイルを小さくしたい場合は,VACUUM FULLまたはCLUSTERコマンドを実行する必要があります。そして多くの場合,VACUUM FULLよりもCLUSTERコマンドを使うほうが適切です。CLUSTERコマンドは一時的に対象のテーブルと同程度の空き領域がディスクに必要となるものの,テーブル再編成の処理が高速に行え,サービスへの影響を極小化できます。

参照も更新も邪魔をせずに同様のメンテナンスを行えるツールとして,PostgreSQLの拡張ツールのpg_repackがあります。pg_repackはもともと同様の意図で開発されていたpg_reorgの後継ツールです。メンテナンスなどで大量のデータを削除した場合などは,pg_repackの利用を検討してください。日本語ドキュメントも公式で用意されています。

VACUUMのそのほかの大事な役割

VACUUMのそのほかの重要な役割として,不要になったトランザクションID(以下,XID)の回収と統計情報の更新があります。

統計情報の更新についてはご存じの人も多いと思いますので割愛します。

XIDの回収についてですが,PostgreSQLはテーブルやレコードなどをそれぞれ一つ一つのオブジェクトとして扱っており,それぞれにIDを割り振っています。これがXIDです。XIDには32ビットの符号なし整数の制約があり,約42億(2^32-1)でXIDは周回します。実際には約42億の半分の値である20億を再利用しており,それ超えるようなトランザクションが発生した場合,XIDを使い切り,XID周回問題が発生します。

XID周回問題は,残り1,000万トランザクションで警告され,残り100万トランザクションから新しいトランザクションはエラーになるため,基本的には発生しません。ですが,発生した場合は古いXIDが割り当てられていたレコードが突然参照できなくなるなどの問題が発生します。これを防ぐために,VACUUMで利用していないXIDを回収し,再利用できるようにしています。

可視性マップ─⁠─追記型アーキテクチャの問題改善

VACUUMは参照されていないデータファイルを再利用できるように処理するしくみと説明しました。それでは,VACUUMは参照されていないデータファイルをどうやって探しているのでしょうか。

そのために利用するのが,前述した共有メモリの可視性マップVisibility Mapです。可視性マップは,ページとして対象のページが参照できるかどうかのフラグをまとめたものです。未更新ですべて見える状態(all-visible)のときには1,更新されて見えないデータがある場合には0が設定されます。all-visibleなページはVACUUMする必要がないため,VACUUMがスキップされます注1)⁠つまり,すべてのページがallvisibleな場合,VACUUMはデータファイルの更新をすべてスキップし,すぐさま終了します。

逆に可視性マップのすべてが0の場合,VACUUMはすべてのデータを更新する必要があるため,対象のテーブルをテーブルフルスキャンで処理します。

このように,PostgreSQLはVACUUMの処理改善のためのしくみを用意しています。

注1)
正確には,32個以上のall-visibleが続いている場合に該当箇所がスキップされます。

INDEX ONLY SCAN─⁠─最速の実行計画

可視性マップは,VACUUMの手助けのほかにも大事な役割があります。それがINDEX ONLY SCANのサポートです。INDEX ONLY SCANはとても高速に参照できるため,PostgreSQLを使ううえでぜひ覚えておきたい機能です。

INDEX ONLY SCANのしくみ

INDEX ONLY SCANはその名のとおり,インデックスのみを利用して検索結果を返すしくみです。

通常,インデックスを利用する際は,次の流れで検索結果を返します。

  1. インデックスから該当のレコードを把握する
  2. インデックスをもとに該当のレコードにアクセスし,データを取得する
  3. 検索結果を返す

INDEX ONLY SCANの場合,2.を省略して検索結果を返すことができます。手順が1つ減るわけですから,高速に返せるのは当然ですね。

INDEX ONLY SCANが使われる定番クエリに,SELECT COUNT(*) FROM table_name;があります。これは,INDEX ONLY SCANが使える状態であれば主キーだけで検索結果を作ることができます。基本的にCOUNT()は遅くなりやすい処理ですから,INDEXONLY SCANのことを覚えておいて損はありません。

ほかにも,SELECT indexed_col FROM table_name WHERE indexed_col in (1, 2, 3);のように検索条件と検索結果,ともにインデックスのみで返せる場合はINDEX ONLY SCAN が使われます。さらにINCLUDE句を利用すると,インデックスに参照用の列を指定できます。

INCLUDE句はMySQLのカバリングインデックスの振る舞いとよく似ており,インデックスのみで検索,データの取得が達成できる場合はとても高速に結果を返せます。

INDEX ONLY SCANの制約

良いことずくめのINDEX ONLY SCANですが,利用するための制約があります。INDEX ONLY SCANを利用するためには,インデックスの情報が最新である必要があります。

実は,PostgreSQLはインデックスには更新情報の有無自体は持っていません。そのため,可視性マップをもとに更新情報の有無を判断しています。可視性マップを見れば,テーブルがall-visibleかどうかを判断できます。テーブルがすべてall-visibleな場合,更新されていないためインデックスの中の情報はどのトランザクションから見ても最新と言えます。つまり,allvisibleであればインデックスの値を返しても問題ないため,INDEX ONLY SCANを利用できます。

ここまで読んでお気付きかもしれませんが,INDEX ONLY SCANを利用するためには,VACUUMが実行されてから対象のテーブルに更新,削除,追加が実行されていないことが必須です。この制約は多くのテーブルでは実現が難しいものです。しかし,INDEX ONLY SCANができる場合の速度は大きなメリットがあるため,更新がされにくい都道府県マスタや更新頻度が少ないテーブルでは絶大な効果を発揮します。物理設計時にINDEX ONLY SCANの選択肢も覚えておくと,設計の選択肢が広がることでしょう。

まとめ

PostgreSQLの基本を知るというテーマで,内部構造を中心に紹介しました。PostgreSQLの内部構造はとても奥が深く,学び甲斐のあるミドルウェアです。

PostgreSQLの内部構造は日本語ドキュメントも豊富で,初学者から上級者まで全員に優しいことも特徴です。これを機に本格的に学びたい人に,PostgreSQL 10ベースですがこれからはじめる PostgreSQL入門注2[改訂新版]内部構造から学ぶPostgreSQL 設計・運用計画の鉄則注3がお勧めです。

注2)
高塚遙,桑村潤著『これからはじめる PostgreSQL入門』技術評論社,2018年
注3)
勝俣智成,佐伯昌樹,原田登志著『⁠改訂新版]内部構造から学ぶPostgreSQL 設計・運用計画の鉄則』技術評論社,2018年
WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.112

2019年8月24日発売
B5判/168ページ
定価(本体1,480円+税)
ISBN978-4-297-10787-1

  • 特集1
    React/Vue.jsで実践!
    コンポーネント設計
    モダンフロントエンドの構造化と分割の新提案
  • 特集2
    RDBMS徹底比較
    PostgreSQL,MySQL,SQL Server,Oracle Database
  • 特集3
    実践Scala
    オブジェクト指向×関数型
  • 一般記事
    自作キーボードのススメ
    デザイン,配列,打鍵感……自由自在

著者プロフィール

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

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

@soudai1025
はてなid:Soudai

著書