やあ。今日もデータベースの沼に浸かってるかい?
今日は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. 「やりすぎ」に注意
パーティションの数が数千個を超えると、今度はプランナが実行計画を作成する時間(パース時間)が無視できなくなる。データ量に応じて、適切な粒度で切るのが腕の見せ所だよ。
—
どうだい? イメージは掴めたかな。
パーティショニングは、設計の段階で「このデータはどういう単位で増え、どういう単位で消えるのか」を深く考える必要がある。面倒に感じるかもしれないけれど、このひと手間が、数年後の「重いクエリ」を未然に防いでくれるんだ。
まずは手元の開発環境で、小さなテーブルから試してみてくれ。インデックスのツリー深さが減っていくのを実行計画で確認するのは、エンジニアとして結構な快感だからね。
それじゃ、また現場で会おう。健闘を祈るよ!
コメント