パーティション数を増やしすぎて発生した性能劣化とその改善
はじめに
あるプロジェクトにおいて、トランザクションテーブルをOracleからPostgreSQLへ移行した際に、特定の処理の性能が大きく劣化する問題が発生しました。本記事ではその原因と対応策について、実行計画の確認方法やパーティション設計の見直しを交えて紹介します。
問題の概要
- Oracle → PostgreSQL への移行を実施
- 対象はトランザクション系の大規模テーブル
- 移行前は「コンマ何秒」で終わっていた処理が、移行後は「数秒」かかるように…
🔍 実行計画の確認
Oracleでの実行計画確認
EXPLAIN PLAN FOR
SELECT * FROM transaction_table WHERE transaction_date = TO_DATE('2025-07-01', 'YYYY-MM-DD');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PostgreSQLでの実行計画確認
EXPLAIN ANALYZE
SELECT * FROM transaction_table WHERE transaction_date = DATE '2025-07-01';
PostgreSQLでの実行計画例(抜粋)
Gather
-> Append
-> Seq Scan on transaction_table_20250701
Planning Time: 1500.000 ms
Execution Time: 50.000 ms
実行計画の構築自体に1.5秒以上かかっており、明らかにオーバーヘッドが大きい状態でした。
原因の特定
- PostgreSQLではパーティション数が多すぎると実行計画の構築に時間がかかる傾向がある
- Oracleでは問題なかったが、PostgreSQLではレンジパーティションの範囲を細かくしすぎた
- さらに、レンジ+ハッシュの多段パーティション構成にしていたことで、パーティション数が爆発的に増加
🛠️ 実際の対応策
✅ ハッシュパーティションを廃止し、レンジパーティションのみに変更
PostgreSQLでのパーティションテーブル作成例
CREATE TABLE transaction_table (
id BIGINT NOT NULL,
transaction_date DATE NOT NULL,
amount NUMERIC,
PRIMARY KEY (id, transaction_date)
) PARTITION BY RANGE (transaction_date);
CREATE TABLE transaction_table_202507 PARTITION OF transaction_table
FOR VALUES FROM ('2025-07-01') TO ('2025-08-01');
CREATE TABLE transaction_table_202508 PARTITION OF transaction_table
FOR VALUES FROM ('2025-08-01') TO ('2025-09-01');
パーティション数を月単位 → 四半期単位に変更することで、計画構築時間が大幅に短縮されました。
💡 その他の改善案
- 古いデータはアクセス頻度が低いと仮定し、広めのレンジ(例:年単位)でパーティションを定義
-
DEFAULTパーティションを活用して、範囲外データの挿入エラーを防止
🔗 参考にした記事
✍️ おわりに
PostgreSQLではパーティション数が多すぎると逆に性能が劣化するケースがあります。Oracleと同じ感覚で設計するとハマるポイントなので、移行時には実行計画の確認とパーティション設計の見直しが重要です。