【実務・中級編】 タプルの可視性 – PostgreSQL

なぜ、PostgreSQLは「見えているはずのデータ」を隠すのか? ― MVCCとタプル可視性の深淵

現場でPostgreSQLを触っていると、たまに「あれ、さっきコミットしたはずのデータがまだ見えないぞ?」とか、「更新したはずなのに古い値が出てくる…」なんて経験、一度はあるよね。

実はこれ、PostgreSQLの心臓部であるMVCC(多版型同時実行制御)が、裏側でめちゃくちゃ頭を使って判断しているからなんだ。今日は、この「タプルの可視性(Visibility)」という、データベースエンジニアなら避けては通れない、でも意外と奥が深いテーマについて、コーヒーでも飲みながら話そうと思う。

—

「見える・見えない」を決めるのは誰か?

PostgreSQLでは、レコード(タプル)を更新しても、古いデータを物理的に消すことはしない。その代わり、新しいバージョンのタプルを書き込み、古いタプルに「もう君は古いよ」というフラグを立てる。

これによって、「読み取り」と「書き込み」が互いにブロックし合わずに動けるんだけど、ここで問題になるのが「今、このトランザクションから見て、どのタプルが『正解』なのか?」という判定だ。

この判定を担っているのが、タプルヘッダーにある2つの隠し列だ。

  • xmin: このタプルを作成したトランザクションID
  • xmax: このタプルを削除(または更新)したトランザクションID

PostgreSQLは、この「トランザクションID」と、現在のトランザクションの「スナップショット」を照らし合わせて、ミリ秒単位で「お前は見える!」「お前はまだ早い!」と判定しているんだ。

具体的な判定ロジック:脳内のイメージ

もし君が「今まさに実行中のトランザクション」だとしたら、DBエンジンはこんな感じでタプルをチェックしているよ。

1. xmin が「すでにコミット済み」かつ「自分のスナップショットより前」なら?
→ おめでとう、君は見える!
2. xmin が「まだ実行中(自分より後)」なら?
→ ごめん、まだそのデータは存在しないことにするね(未コミットのデータは見せない)。
3. xmax が「すでにコミット済み」なら?
→ そのデータはもう削除されたものとして扱うよ。

このロジックのおかげで、PostgreSQLは「行レベルロック」を極限まで減らして、爆速な読み取り性能を実現しているんだ。

—

実践:その「見え方」を覗き見る

理論だけじゃつまらないから、実際にどうなっているか見てみよう。PostgreSQLには、内部構造を覗くための最高の武器がある。`pageinspect` 拡張モジュールだ。

— 事前準備:モジュールの有効化
CREATE EXTENSION pageinspect;

— テーブル作成とデータ挿入
CREATE TABLE test_table (id int, val text);
INSERT INTO test_table VALUES (1, ‘Hello’);

— 内部構造を確認
SELECT lp, t_xmin, t_xmax, t_ctid
FROM heap_page_items(get_raw_page(‘test_table’, 0));

ここで表示される `t_xmin` や `t_xmax` が、まさにさっき話した「可視性の判定基準」そのものだ。

もしトランザクションを分けてみてみると面白い。

  • トランザクションAで `UPDATE` をかける。
  • その瞬間に別のトランザクションBから `SELECT` して、`t_xmin` を比較してみる。

「あ、更新前と後で、別の物理行が作られているな」と直感的に理解できるはずだよ。これが分かると、「なぜ頻繁なUPDATEがVACUUMを呼ぶのか」という理由も、腹落ちするようになる。

—

現場のエンジニアへのアドバイス:なぜこれを知る必要があるのか?

「仕組みなんて知らなくてもSQLは書けるよ」と思うかもしれない。でも、この知識が役立つ瞬間は必ず来る。

例えば、「ロングトランザクションによるテーブル肥大化(Bloat)」の問題だ。
長い時間終わらないトランザクションがいると、PostgreSQLは「まだ古いデータが参照されているかもしれない…」と判断して、古いタプルを消せずに残し続ける。その結果、テーブルサイズが膨れ上がり、クエリが遅くなる。

「なんか最近クエリが遅いな」というとき、原因はインデックスの張り忘れじゃなくて、実はこういう「可視性の判定が複雑になりすぎていること」にあるケースが意外と多いんだ。

最後に

タプルの可視性は、PostgreSQLの「信頼性」と「同時実行性」を両立させるための、最高にエレガントな仕組みだ。教科書を丸暗記するんじゃなくて、「今、DBの中で何が起きているか」を脳内でシミュレーションできるようになると、トラブルシューティングのレベルが一段階上がるはずだよ。

何か疑問があったら、またいつでも聞いてくれ。現場からは以上だ!

コメント

タイトルとURLをコピーしました