ハッシュ結合の深淵:PostgreSQLが大規模データを「捌く」とき
PostgreSQLのクエリプランナーと夜通し対峙した経験がある方なら、一度は目にしたことがあるはずです。「Hash Join」。
ネステッドループで力技に挑むか、マージ結合で整列の恩恵に預かるか。その中で、ハッシュ結合は「計算量 $O(N+M)$」という圧倒的なパフォーマンスの暴力で、大規模なデータセットをねじ伏せるための切り札です。しかし、この切り札も、その内側の挙動を理解せずに振り回せば、システムを根底から揺るがす「メモリのブラックホール」へと変貌します。
今回は、PostgreSQLにおけるハッシュ結合の内部構造と、それが崩壊する瞬間――いわゆる「ディスクへの溢れ(spill to disk)」――について、少し深掘りしてみましょう。
—
ハッシュ結合のライフサイクル:メモリという名の戦場
ハッシュ結合のプロセスは、非常にシンプルです。まず「ハッシュテーブルの構築(Build Phase)」を行い、次に「プローブ(Probe Phase)」を行う。この二段構えです。
1. Build Phase (Inner Relation): 結合条件のキーをハッシュ関数に通し、メモリ上にハッシュテーブルを構築します。ここで最も重要なのが、PostgreSQLの構成パラメータ `work_mem` です。
2. Probe Phase (Outer Relation): 続いて外側のテーブルを走査し、各レコードのキーで同じハッシュ関数を叩き、テーブル内の該当エントリと突き合わせます。
ここでエンジニアが最も警戒すべきは、「メモリが足りなくなった時」です。
work_mem を超えた先に待つ「悲劇」
`work_mem` は、単一の結合操作(あるいはソート操作)に対して割り当てられるメモリ上限です。もし、構築しようとしているハッシュテーブルのサイズが `work_mem` を超えると、PostgreSQLはハッシュテーブルを小さな「バケット」に分割し、一部をディスク(一時ファイル)へ退避させ始めます。
これが「Spill to disk」です。ログに `temporary file` が吐き出され始めたら、それは性能劣化の合図です。
- なぜ遅くなるのか: 単純なディスクI/Oのオーバーヘッドだけではありません。ディスクに書き出されたデータは、再度読み込む際にランダムアクセスを伴うことが多く、CPUのキャッシュ効率も劇的に低下します。
- マルチパス・ハッシュ結合: ディスクに溢れた場合、PostgreSQLはハッシュテーブルを階層化して再構築します。このオーバーヘッドは、メモリ上に収まっていた時に比べ、桁違いの負荷をクエリに与えます。
パフォーマンストラブルの現場で何をすべきか
もし、実行計画(EXPLAIN ANALYZE)を見て `Batches: N` や `Disk: NkB` という記述を見つけたら、それは「チューニングの余地あり」というサインです。
1. work_mem の最適化は慎重に
「とりあえず大きくしよう」という判断は危険です。`work_mem` は同時接続数分だけ消費される可能性があるため、安易に巨大化させるとOOM Killer(Out of Memory Killer)を呼び寄せることになります。`SET LOCAL` を使い、特定の重たいバッチ処理やクエリに対してのみ、一時的に大きなメモリを割り当てるのが、熟練者の作法です。
2. 統計情報の鮮度を疑う
ハッシュ結合がディスクに溢れる原因の多くは、プランナーが「ハッシュテーブルのサイズを過小に見積もる」ことに起因します。`ANALYZE` を実行し、プランナーがテーブルのカーディナリティ(データの分布やユニーク数)を正確に把握できているかを確認してください。統計情報が古いと、プランナーは「メモリに収まるはず」と誤算し、結果としてディスクへ溢れる悲惨なプランを生成します。
3. 結合キーの型を合わせる
意外な盲点ですが、結合キーのデータ型が異なると、ハッシュ関数の計算や比較において無駄な型変換コストが発生します。インデックスが効かないだけでなく、ハッシュテーブルの構築効率にも悪影響を及ぼすため、型の一致には細心の注意を払いましょう。
—
最後に:ハッシュ結合は「魔法」ではない
ハッシュ結合は強力ですが、万能薬ではありません。データが小規模ならネステッドループの方が速いこともありますし、既にインデックスでソートされているならマージ結合の方が効率的です。
私たちがデータベースエンジニアとして行うべきは、クエリに最適な「道」を提示することです。ハッシュ結合の内部で何が起きているか、メモリのどこでデータが滞留しているかを想像できるようになれば、PostgreSQLはあなたの意のままに動く最強の武器になります。
次に `EXPLAIN ANALYZE` を叩くとき、ぜひその裏側にある「ハッシュテーブルの構築」というドラマに想いを馳せてみてください。そこには、OSとメモリ、そして効率化への執念が詰まっているのですから。
それでは、また次回の深淵でお会いしましょう。
コメント