宣言的パーティショニング:PostgreSQLで「巨大なテーブル」を飼い慣らすための作法
PostgreSQLの運用歴が長くなると、必ず直面する壁がある。数億行、あるいは数十億行に達した巨大テーブルだ。かつては `inherit` を使った力技の継承テーブル設計で凌いできたものだが、PostgreSQL 10以降、ようやく我々が待ち望んでいた「宣言的パーティショニング」が標準機能として実装された。
今回は、この「宣言的パーティショニング」の裏側と、大規模DBのパフォーマンスを維持するためのインデックス戦略について、教科書には載っていない(載っていても読み飛ばされがちな)現場の知見を共有したいと思う。
—
なぜ今、宣言的パーティショニングなのか
昔ながらの継承パーティショニングは、制約チェックやトリガーによるルーティングが必要で、正直なところ「運用者の気合」に依存する部分が大きかった。一方、`CREATE TABLE … PARTITION BY` を用いた宣言的パーティショニングは、クエリプランナがパーティションの構造を「最初から知っている」点が決定的に違う。
クエリプランナは `WHERE` 句の条件を見て、対象外のパーティションを即座に無視する。これが有名なパーティションプルーニング(Partition Pruning)だ。これにより、数TBのデータがあっても、数MBの小さなインデックスだけを走査してクエリが完了する。この爽快感は、一度味わうと手放せない。
3つの戦略:RANGE, LIST, HASH
設計の基本だが、ここにはエンジニアの哲学が出る。
- RANGEパーティショニング: 時系列データには最適だ。「先月のデータはアーカイブへ、今月のデータは高速ストレージへ」といったライフサイクル管理が容易になる。
- LISTパーティショニング: 地域コードやステータスなど、カテゴリが明確な場合に適している。ただ、キーの偏りには注意が必要だ。特定のパーティションだけが肥大化すると、結局ボトルネックになる。
- HASHパーティショニング: 負荷分散の最終兵器だ。キーのカーディナリティが高い場合、データが均等に分散されるため、特定のパーティションにI/Oが集中するのを防げる。ただし、範囲指定(`range query`)にはめっぽう弱いので注意が必要だ。
—
パフォーマンストラブルの「深淵」を覗く
さて、ここからが本題だ。宣言的パーティショニングを使えば万事解決かというと、そうではない。現場でよく見る「ハマりポイント」をいくつか挙げておこう。
1. プルーニングが効かない「インデックスの罠」
クエリがインデックスを貼っているはずなのに、なぜか全パーティションをスキャン(Full Table Scan)している……そんな経験はないだろうか。
原因の多くは「型の一致」だ。例えば、パーティションキーが `BIGINT` なのに、クエリの `WHERE` 句で `VARCHAR` の値を渡していれば、暗黙の型変換が走り、プランナは「安全策」をとって全パーティションを覗きに行くことになる。`EXPLAIN` を叩いて `Subplans Removed` の項目を確認するのは、エンジニアの嗜みだ。
2. パーティションの細分化という落とし穴
「パーティションを細かく分ければ分けるほど速い」と信じているエンジニアがいるが、これは大きな誤解だ。
パーティションが増えすぎると、プランナの解析コストが跳ね上がる。数千個のパーティションを持つテーブルに対して `INSERT` や `SELECT` を投げれば、それだけでCPUを食いつぶすことになる。適切な粒度は、データ量だけでなく「一度のクエリでアクセスする範囲」を基準に決めるべきだ。
3. グローバルインデックスの欠如
PostgreSQLのパーティショニングにおいて、現状「ユニーク制約」はパーティションキーを含まなければならない。これは分散DBとしての制約だが、実務上はかなり制約が強い。もし「パーティションを跨いで一意性を保証したい」という要件があるなら、それはアプリケーション層での工夫か、あるいは `pg_partman` のような拡張機能を使いこなす、あるいはそもそもアーキテクチャを見直す必要がある。
—
エンジニアとしての「感触」
大規模なデータセットを扱うとき、私は常に「データがどこにあるか」を直感的にイメージできるように設計を組む。
`CREATE TABLE … PARTITION BY` は、単なるDDLではない。それはデータに対する「地図」を作ることだ。適切に設計された地図は、クエリを目的地まで最短ルートで導いてくれるが、設計を怠れば、プランナという優秀なガイドは迷子になり、システム全体が悲鳴を上げる。
最後にアドバイスを一つ。「とりあえず作ってから考える」のはやめよう。
`EXPLAIN ANALYZE` を徹底的に読み込み、パーティションプルーニングが機能しているか、インデックスが効果的に効いているか。その「感触」を研ぎ澄ませることが、DBエンジニアとして一段上のステージに上がるための近道だと、私は信じている。
さて、今日はここまで。また、深い技術の話でお会いしよう。
コメント