パーティション分割を使用した Heroku Postgres 上の大きなテーブルのパフォーマンスの向上
最終更新日 2023年02月15日(水)
アプリケーションやそれに関連付けられているデータボリュームが増加すると、Postgres データベース内のいくつかのテーブルは他のテーブルよりはるかに速い速度で増加します。これにより、アプリケーションでさまざまな問題が発生する場合があります。アプリケーション内のクエリ時間が増加し始め、一括ロードの時間が長くなるほか、インデックスの作成に長い時間がかかる可能性があります。この問題を解決するための 1 つの方法は、論理的に 1 つの大きなテーブルをより小さな物理的な部分へパーティション分割することです。
テーブルのパーティション分割は最後の手段として使用してください。テーブルをパーティション分割しようとする前に、「Heroku Postgres データベースのチューニング」の記事を参照してください。
概要
Postgres の場合、テーブルをパーティション分割するには、すべての子テーブルが継承するマスターテーブルが存在する必要があります。子テーブルはそれぞれ手動で作成する必要があり、マスターテーブルから継承されたものの他に余分な列を作成しないでください。唯一の注意事項は、それぞれの子テーブルにインデックスを作成する必要があることです。挿入されるデータが正しいパーティションに確実に移動されるようにするために、一連の CHECK 制約が作成されます。
テーブルをパーティション分割するための主なユースケースには通常、時系列を通して作成されるデータを追跡するテーブルの取得が含まれます。他のユースケースも存在しますが、他のタイプのテーブルでも、このドキュメントで説明されているプロセスに従うことができます。
pg_partman
pg_partman
は、時間ベースとシリアルベースの両方のテーブルパーティションセットを作成して管理するための拡張機能です。子テーブルとトリガー関数の作成はすべて、この拡張機能自体によって管理されます。既存のデータを含むテーブルも、容易に管理できるより小さなバッチにデータをパーティション分割できます。オプションの保持ポリシーで、必要なくなったパーティションを自動的に削除できます。パーティション管理は pg_partman
によって処理されますが、パーティションの管理を適切な間隔で起動するには、Postgres に対する外部のスケジューリングサービスが必要です。
この例では、イベントテーブルのパーティション分割を実行します。
セットアップ
拡張機能をロードする
マスターテーブルをパーティション分割するには、データベースに拡張機能を追加しておく必要があります。$ heroku pg:psql -a sushi sushi::DATABASE=> CREATE EXTENSION pg_partman;
マスターテーブルを定義する
ほとんどの場合は、テーブルのデータの増加がきわめて大きいため、マスターテーブルはすでに定義されています。たとえば、イベントを次のように定義できます。$ heroku pg:psql -a sushi sushi::DATABASE=> \d events Column | Type | Modifiers ------------+--------------------------+----------- id | integer | name | text | type | text | created_at | timestamp with time zone | not null
パーティション分割する時間間隔を決定する
この間隔は、作成されるデータの速度によって異なります。経験則として、パーティションは 1 時間未満ではありません。パーティションウィンドウの標準的な設定は、毎時、毎日、または毎月です。pg_partman
には、パーティションウィンドウを定義するための多くの 異なるオプション があります。初期のパーティションを作成する
psql
コンソール内で、パーティション分割として決定した間隔と保持期間を使用する必要があります。$ heroku pg:psql -a sushi sushi::DATABASE=> SELECT create_parent('public.events', 'created_at', 'time', 'daily');
このコマンドを呼び出すと、
pg_partman
は、子テーブルを管理するためのいくつかの制御テーブルとそれに関連付けられたデータを作成します。プロジェクトにメンテナンススクリプトを追加する
pg_partman
は、自動的にテーブルをパーティション分割し、それに関連付けられたトリガーを管理することができないため、パーティションを管理するには、Heroku Scheduler やクロックプロセスなどの外部のスケジューリングサービスが必要です。常に古いパーティションが削除され、新しいパーティションが作成されるようにするには、データベースに対して定期的なメンテナンスタスクを実行する必要があります。Heroku Scheduler を使用してデータベースに対して実行されるコマンドの例を次に示します。psql $DATABASE_URL -c 'select run_maintenance();'
テーブルのパーティション分割に使用される時間間隔に応じて、毎時または毎日実行されるように Heroku Scheduler を設定します。
Postgres でのテーブルのパーティション分割を開始するには、この設定プロセスで十分です。pg_partman
を使用すると、さらに多くの方法で設定できます。
パーティション分割のより高度な設定については、Github 上のpg_partman
ドキュメントを参照してください。
制限と注意事項
Postgres でのテーブルのパーティション分割は、アプリケーションによって生成されるデータの速度を管理するために役立ちますが、いくつかの制限が存在します。
- 子テーブルの名前の長さは最大 63 文字までです。作成される子テーブルの名前が最大の長さを超えると、切り捨てられるため、予期しない結果を招くことがあります。
- 子テーブルの数を保持しているジョブが長期間にわたって停止し、子テーブルが作成されない場合は、
INSERT
ステートメントが拒否され始めます。 - このドキュメントの例やパーティションを管理するためのコードは、時系列データでパーティション分割する必要があるテーブルのみを対象にしています。
create_parent
の実行後にERROR: permission denied for schema heroku_ext
メッセージを受け取る場合、これらの 手順 に従ってください。