パーティショニング — Issue グループ検索
データベースパーティショニング: Issue グループ検索
特定の例を見ながらデータベースパーティショニングの必要性を説明してきました。グループベースの Issue 検索です。
このタイプの検索は、GitLab グループ内(gitlab-org グループの例)で特定の Issue を見つけることを可能にします。マイルストーン、作成者、またはフリーテキスト検索でフィルタリングするなど、あらゆる種類のフィルターを適用できます。
このドキュメントは、PostgreSQL 11 を使用した本番規模のデータセットで Issue グループ検索のデータベースパーティショニングを探索した結果をまとめたものです。
セットアップ
GitLab.com の本番データのコピーから始め、データベースを PostgreSQL 11 にアップグレードしました(パーティショニング機能を活用するため)。このデータセットは、本番データベースのレプリカインスタンスに相当する GCP インスタンス(インスタンスタイプとディスクサイズの面で)に存在しています。
このデータベースで、64パーティションを持つパーティショニングされた issues テーブルを作成し、Issue(とそのプロジェクト)が属するトップレベルネームスペースによるハッシュベースのパーティショニングを採用しました。これはいくつかのステップで行われました(SQL スクリプト):
- 各 Issue のトップレベルネームスペース情報を計算する。
- パーティショニングキーとして機能する追加の
top_level_namespaceカラムを持つパーティショニングされたテーブルparts2.issuesを作成する。 public.issuesからこのパーティショニングされたテーブルに既存データを移行・コピーする。
クエリ分析
このセットアップに基づいて、2種類のクエリを調べました:
- 通常のフィルターとテキスト検索を組み合わせた複雑な Issue グループ検索
- 1つのプロジェクトの Issue を数えるシンプルなクエリ
どちらのケースも単一のグループに向けられており、ネームスペースに基づくパーティショニングスキームの恩恵を受けることができます。
複雑な Issue グループ検索
このクエリの詳細と結果はIssueで確認できます。この例の特性は以下の通りです:
gitlab-orgグループ内のログインユーザーによるマイルストーンとテキスト検索を組み合わせた Issue グループ検索- ネームスペースを対象としており、パーティショニングから大きな恩恵を受けることが期待される。
結果は以下の通りです:
- 実行時間が約8〜10倍短縮し、ウォームキャッシュでの実行時間が約2秒から0.2秒に減少。
- プランニング時間が約10msから40msへと増加。
プランニング時間の増加は予想通りであり、実行時間が大幅に改善される限り、そのコストに見合います。
シンプルなカウントクエリ
このクエリの詳細と結果はIssueで確認できます。この例の特性は以下の通りです:
- 特定のプロジェクト(
gitlab-org/gitlab)の Issue を数えるシンプルなクエリ - インデックスオンリースキャンをデフォルトとし、大量のデータを読み取らない
- パーティショニングされていない場合のテーブルサイズ(約20 GB)を考えると、このクエリはそもそも大量のデータを読み取っていないため、パーティショニングから大きな改善が見られないことが予想される。
結果は以下の通りです:
- ウォームキャッシュで、合計時間は約29msで、パーティショニングされていない場合と比較してパーティショニングされた場合の方が50%悪い。
- 合計時間の増加は、パーティショニングされたケースでのプランニング時間の大幅な増加(<1msから14msへ)によって支配されている。
テーブルとインデックスのサイズ
予想通り、パーティションとそのインデックスの個々のサイズは大幅に削減されました。特に、パーティション上のインデックスは、パーティショニングされていないテーブルと比較して10倍から100倍小さいです。パーティショニングから得られる主なメリットはここにあります。クエリのほとんどのパーティションを静的に除外できる場合、小さいインデックスと小さいテーブルのみを扱うことになります。
プランニング時間
クエリプランニング時間をより詳しく調べました。先ほどのクエリ分析中に、パーティショニングされたケースでプランニング時間の増加に気づきました。これは予想通りです。プランナーはパーティションをプルーニングし、より多くのテーブル(各パーティションは独自のものを持つ)のメタデータと統計を処理する必要があります。
アタッチされたパーティション数が変化する際のプランニング時間を調査しました。
ベンチマークは、パーティションを再編成し、目的のパーティション数をテーブルにアタッチした後、同じクエリに対して5回実行しました。キャッシュの動作により、最初の試行とその後の試行を区別します。
さらに、ここでは2つのケースを見ています:
- パーティショニングキーありのクエリ:
WHERE project_id = ? AND root_namespace_id = ? - パーティショニングキーなしのクエリ:
WHERE project_id = ?
2番目のケースは明らかに、すべてのパーティションをスキャンするため、実行中のパーティショニングの恩恵を受けられません。
シンプルなクエリから始めると、これはかなり予想通りの結果を示します。ご覧の通り、プランニング時間はアタッチされたパーティション数に依存し、パーティション数が増えるにつれてわずかに増加します。最初の試行では、コールドキャッシュ(テーブルメタデータ、統計)によりプランニング時間が高くなっています。

2番目の例では、同じ分析を採用しますが、複雑な Issue グループ検索の例を見ています。パーティショニングキーなしのケースで、かなり予想外のプランニング時間が示されました。これは、パーティショニングキーをフィルターとして持たないクエリに大きな悪影響を与えます。

これは比較的大きな統計を収集することが原因かもしれないと疑いました。GitLab.com では現在 default_statistics_target = 1000 を使用しており、これはデフォルトの postgres 設定の10倍です。これはテーブルのヒストグラムが持つ詳細度を直接制御し、クエリプランニングに関連するデータに直接影響します。
これを default_statistics_target = 100(デフォルト設定)に下げると、より合理的なクエリタイミングに達します。幸いなことに、この設定はテーブルごとに制御することもできます。

これらのグラフのすべてのデータは公開シートで確認できます。
得られた知見
- テーブルパーティショニングは予想通り実行時間を削減するのに役立つ。
- ほとんどのパーティションがプルーニングされるケースでプランニング時間が増加する。これも予想通りで、その後の実行時間を大幅に削減できる場合にコストに見合う。
- パーティショニングキーのないクエリには注意が必要。
パーティショニングキーのないクエリ
パーティショニングはクエリがパーティショニングキーのフィルターを含む場合にのみ機能します。その場合にのみ、プランナーは実行プランから無関係なパーティションを除外できます。
パーティショニングキーのないクエリについては、パーティショニングがそのプランニング時間にも影響を与えることを知っておくことが重要です。これは上記に示したように大きな問題になる可能性があり、パーティショニングされたテーブルの統計サイズを削減することを検討する必要があります。パーティショニングキーのないクエリが、パーティショニングなしと同じレベルのパフォーマンスを発揮することは期待できません。
これにより、テーブルパーティショニングの反復的な導入が難しくなります。パーティショニングされたテーブルを元のテーブルの代わりに使用するように切り替えると、パーティショニングキーのないクエリで問題が生じるリスクがあります — 上記に示したように大きな問題になる可能性があります。
これは、パーティショニングされたテーブルに対して、できるだけ多くのクエリがパーティショニングの恩恵を受け、自然にパーティショニングキーフィルターを使用するようにする必要があることを意味します:
activerecord-multi-tenantを使用すると、可能な場合にパーティショニングキーを自動的に導出してこのフィルターを追加できます。- 開発サイクルの早い段階(つまり CI 上で)でパーティショニングキーを含まないクエリを検出・発見するメカニズムを見つけたい。
- パーティショニングキーをまったく使用できないケースもあります。
例えば、ユーザーに割り当てられた Issue を見つけることは、ネームスペースの概念ではなく、ユーザーの視点から来ます。これらのケースを特定して解決する必要があります。例えば、それらの機能を別のサービスに抽出したり、データを内部的に複製したり(例: 割り当てテーブルを両方の視点を効率的にサポートするために)、また場合によってはプランニング時間の増加を受け入れることも可能です。
PostgreSQL テーブルパーティショニングに関する作業ページ
GitLab のデータベースへの PostgreSQL テーブルパーティショニングの導入に関する作業ページも参照してください。
著者: Andreas Brandl
