【実務・中級編】 宣言的パーティショニング – PostgreSQL

やあ。今日もデータベースの沼に浸かってるかい?

今日はPostgreSQLの「宣言的パーティショニング」について話そうと思う。これ、大規模なデータセットを扱うときには避けて通れない……いや、むしろ積極的に使ってほしい強力な武器なんだ。

ドキュメントを読めば構文は載っているけれど、実務でどう使い分けるべきか、そして「なぜ速くなるのか」という核心部分は、現場の経験がないとなかなか腹落ちしないよね。今日はそこを深掘りしていくよ。

—

そもそも、なぜパーティショニングするのか?

結論から言うと、「巨大なテーブルを、管理可能な小さな塊に分けること」だ。

インデックスを貼るだけじゃ限界があるケースってあるよね。数億行のテーブルでインデックスの肥大化に悩んだり、古いデータを消すために`DELETE`を打ってVACUUMの負荷に泣いたり……。パーティショニングすれば、特定のパーティションを切り離す(DROP TABLE相当の操作)だけで、瞬時にデータ削除が完了する。これが運用上の最大のメリットだ。

—

3つのパーティショニング方式:使い分けの指針

PostgreSQLでよく使うのはこの3つだ。

1. RANGEパーティショニング(時系列データの王様)

日付やIDの範囲で分割する。ログや決済履歴など、「古い順から消したい」という要件ならこれ一択。

CREATE TABLE orders (
order_id bigint,
order_date timestamp NOT NULL,
amount decimal
) PARTITION BY RANGE (order_date);

— パーティションの作成
CREATE TABLE orders_2023_q4 PARTITION OF orders
FOR VALUES FROM (‘2023-10-01’) TO (‘2024-01-01’);

2. LISTパーティショニング

「特定のカテゴリ」に分類する場合に使う。「地域別」「ステータス別」といった、値が固定的なものだね。

CREATE TABLE users (
user_id int,
region text
) PARTITION BY LIST (region);

CREATE TABLE users_tokyo PARTITION OF users FOR VALUES IN (‘Tokyo’);

3. HASHパーティショニング

「データが均等に散らばるようにしたい」とき、あるいは特定の範囲に偏らせたくないときに使う。ハッシュ関数で自動的に振り分けるから、特定のパーティションだけが極端に肥大化するのを防げる。

CREATE TABLE sensor_data (
sensor_id int,
reading float
) PARTITION BY HASH (sensor_id);

CREATE TABLE sensor_data_p1 PARTITION OF sensor_data FOR VALUES WITH (MODULUS 4, REMAINDER 0);

—

魔法の仕組み:「パーティションプルーニング」

ここが一番面白いところだ。パーティショニングしただけでは、クエリは速くならない。「不要なパーティションを無視する」という最適化機能、それがパーティションプルーニング(Partition Pruning)だ。

例えば、`order_date`でRANGEパーティショニングしているテーブルに対して、こんなクエリを投げたとしよう。

SELECT FROM orders WHERE order_date = ‘2023-11-15’;

PostgreSQLのクエリオプティマイザは、「あ、この日は`orders_2023_q4`のパーティションにしかないな」と判断して、他のパーティション(2023年Q3や2024年Q1など)を検索対象から完全に除外する。

これが劇的に速い理由だ。 インデックスを全スキャンする手間が省け、必要な小さなテーブルだけをピンポイントで叩ける。もし実行計画(`EXPLAIN`)を見て、ここに全パーティションが並んでいたら……それはプルーニングが効いていない証拠だ。クエリの条件式がパーティションキーと合致しているか、必ず確認するようにしよう。

—

先輩からの実践的なアドバイス

最後に、現場でハマりやすいポイントを伝授しておくよ。

1. インデックスはパーティションごとに貼る
親テーブルにインデックスを作れば、自動的に全パーティションに伝播する。だから「全部のパーティションにインデックスを貼るコードを書かなきゃ……」と悩む必要はない。PostgreSQLはそこまで賢い。
2. パーティションキーをWHERE句に入れる癖をつける
パーティションキーをWHERE句で指定しないクエリは、結局全パーティションを走査することになる。これではパーティショニングの恩恵が台無しだ。アプリケーション側で、常に期間指定やカテゴリ指定が漏れないような設計を心がけて。
3. 「やりすぎ」に注意
パーティションの数が数千個を超えると、今度はプランナが実行計画を作成する時間(パース時間)が無視できなくなる。データ量に応じて、適切な粒度で切るのが腕の見せ所だよ。

—

どうだい? イメージは掴めたかな。

パーティショニングは、設計の段階で「このデータはどういう単位で増え、どういう単位で消えるのか」を深く考える必要がある。面倒に感じるかもしれないけれど、このひと手間が、数年後の「重いクエリ」を未然に防いでくれるんだ。

まずは手元の開発環境で、小さなテーブルから試してみてくれ。インデックスのツリー深さが減っていくのを実行計画で確認するのは、エンジニアとして結構な快感だからね。

それじゃ、また現場で会おう。健闘を祈るよ!

コメント

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