【実務・中級編】 HOT更新 (Heap Only Tuple) – PostgreSQL

「PostgreSQLのパフォーマンスが出ない……」

そう嘆く現場で、スロークエリログやテーブルの統計情報を覗いてみると、意外とよくあるのが「インデックスの肥大化」と「不要な書き込み処理」の悪循環です。

今日は、PostgreSQL使いなら絶対に知っておくべき、そして現場で差がつく武器「HOT更新(Heap Only Tuple)」について話をしよう。

教科書的な定義は一旦置いておいて、まずは「なぜHOTが重要なのか」という現場の肌感覚から共有するよ。

—

1. なぜ「普通の更新」は重いのか?

PostgreSQLはMVCC(多版同時実行制御)を採用しているよね。データが更新されるとき、古いレコードを消して新しいものを書くのではなく、古いレコードに「削除フラグ(正確にはXMIN/XMAX)」を立てて、新しく行を追加する。

ここまでは基本だ。でも、もしそのテーブルにインデックスが貼ってあったらどうなる?

PostgreSQLは、インデックスが「どの行を指しているか」という物理的な場所(TID)を保持している。もしインデックス列そのものを更新したなら、インデックスを書き換えるのは当然だよね。

しかし、インデックスに関係のないカラム(例えば `status` フラグだけ変えるとか)を更新したときでも、インデックスまで更新しようとしたらどうなるだろう? 毎回インデックスのツリーを辿って、ポインタを書き換えるコスト。これ、積み重なると相当な負荷になるんだ。

2. HOT更新という「魔法」

ここで登場するのがHOT更新だ。
PostgreSQLは賢い。もし「更新しようとしている行の、同じページ(8KBのブロック)内に空き容量がある」かつ「インデックス列が更新されていない」という条件を満たすなら、インデックスを一切更新せずに、ヒープ領域だけで更新を完結させてしまう。

これがHOT更新の正体だ。

  • インデックスが肥大化しない(インデックスの更新頻度が激減するから、不要なインデックスエントリが生まれない)。
  • I/Oが減る(インデックスページを読み書きしなくて済む)。
  • Vacuumが楽になる(インデックスの整理が必要なくなるからね)。

まさに、現場でパフォーマンスを安定させるための「静かなる功労者」なんだ。

3. HOTを効かせるための「現場の鉄則」

じゃあ、この恩恵をフルに受けるにはどうすればいいか。実は、ここが一番大事なポイントだ。

① `FILLFACTOR` を意識せよ

HOT更新が成功する最大の条件は「同じページ内に空きがあること」だ。デフォルトの `FILLFACTOR` は100(ページをパンパンに詰め込む)になっていることが多い。

頻繁に更新が入るテーブルなら、あえて少し余裕を持たせるのが定石だ。

— テーブル作成時にFILLFACTORを90くらいに設定する
CREATE TABLE users (
id serial PRIMARY KEY,
status text,
updated_at timestamp
) WITH (fillfactor = 90);

こうすることで、ページ内に余白が生まれ、HOT更新が発生する確率がグッと上がる。もちろん、データ量が増えるというトレードオフはあるから、そこはバランス調整が必要だ。

② インデックスを「むやみに」貼らない

当たり前だけど、インデックスは更新の敵だ。必要のないインデックスはHOT更新を阻害するし、そもそも更新そのものを重くする。

③ 更新するカラムに注意を払う

アプリケーションの設計段階で「頻繁に更新されるカラム」と「検索キーになるカラム」を意識的に分けること。検索キー(インデックス対象)を頻繁にUpdateするようなスキーマ設計は、PostgreSQLにおいてはアンチパターンになり得るんだ。

4. 自分のテーブルがHOT更新されているか確認する方法

「理屈はわかったけど、自分のテーブルでHOTが効いてるのかどうやって確認するの?」

そんなときは `pg_stat_user_tables` を見るのが一番早い。

SELECT relname, n_tup_upd, n_tup_hot_upd
FROM pg_stat_user_tables;

`n_tup_upd` が全体の更新回数で、`n_tup_hot_upd` がHOT更新できた回数だ。この比率を見てみてほしい。もし `n_tup_hot_upd` が0に近かったら……君のデータベースは、本来不要なはずのインデックス更新作業で、夜通し必死に汗をかいているかもしれないよ。

—

最後に

HOT更新は、チューニングの「派手な必殺技」ではないかもしれない。けれど、大規模なトラフィックを捌くシステムにおいて、こういう「地味だけど確実に効く」設定をしているかどうかで、数ヶ月後のシステムの安定感は全く変わってくる。

「とりあえずインデックスを貼る」のその先へ。
次にデータベースを設計するときは、ぜひこのHOT更新のことを思い出して、ページ内の空きスペースを意識した設計をしてみてほしい。

それじゃ、現場からは以上だ。また何かあればいつでも聞いてくれ。

コメント

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