すべてのプロダクト
Search
ドキュメントセンター

PolarDB:グローバルインデックス

最終更新日:Dec 27, 2025

グローバルインデックスとは、パーティションテーブルの非パーティションキー列に作成されるインデックスです。グローバルインデックスは、一意制約を適用することもできます。

適用範囲

この機能は、マイナーエンジンバージョンが 2.0.14.9.15.0 以降の PolarDB for PostgreSQL PostgreSQL 14 を実行するクラスターでサポートされています。

説明

マイナーエンジンバージョン番号は、コンソールで表示するか、SHOW polardb_version; 文を実行して確認できます。マイナーエンジンバージョンが要件を満たしていない場合は、マイナーエンジンバージョンをアップグレードできます。

背景情報

ビジネスデータの増加に伴い、データパーティショニングはエンタープライズレベルのデータベースの重要な機能となり、データ規模を縮小するための重要な手法となっています。パーティションテーブルは、パーティションキーに基づいて複数の独立した子テーブルに分割されます。子テーブルは個別に管理され、管理性、全体的なパフォーマンス、負荷分散が向上します。

PolarDB for PostgreSQL および の多くのユーザーは、パーティションテーブルを使用してデータを管理しています。典型的なユースケースは、時間によるデータパーティショニングです。

  • パーティションテーブルのパーティションキーとして時間を使用します。

  • 週次や月次など、定期的に新しいサブパーティションを作成して新しいデータを格納します。

  • 古いサブパーティションを定期的にアーカイブして、パーティションテーブルの運用保守 (O&M) コストを削減します。

上記のシナリオでは、時間は通常パーティションキーとして使用され、プライマリキーや一意の ID としては使用されません。これにより、2 つの問題が発生します。

  • 非パーティションキーを使用してデータをクエリする場合、システムはどのパーティションにデータが含まれているかを判断できないため、すべてのサブパーティションをスキャンする必要があります。

  • 非パーティションキーを使用してデータを変更する場合、パーティションテーブル全体でデータの一意性を保証できません。

これらの問題を解決するために、PolarDB for PostgreSQL および はグローバルインデックス機能を提供します。デフォルトで各サブパーティションに作成されるローカルインデックスとは異なり、単一のグローバルインデックスはパーティションテーブル全体のデータをカバーします。つまり、1 つのインデックスが複数のサブパーティションに対応します。これにより、グローバルな一意性制約を適用し、非パーティションキーでのクエリパフォーマンスを大幅に向上させることができます。

制限事項

  • グローバルインデックスを持つパーティションテーブルからサブパーティションを ATTACH または DETACH することは引き続き可能です。

  • `CREATE INDEX` 文で GLOBAL キーワードを指定して、グローバルインデックスを作成します。このキーワードを指定しない場合、デフォルトでローカルインデックスが作成されます。

  • CONCURRENTLY キーワードを指定することで、グローバルインデックスを同時に作成できます。

  • 非パーティションテーブルやサブパーティションを含む子テーブルには、グローバルインデックスを作成できません。

  • グローバルインデックスは式インデックスをサポートしていません。

  • パーティションテーブルのパーティションキー列にグローバルインデックスを作成することはできません。

構文

グローバルインデックスを作成できます。

CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
    ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
    [ INCLUDE ( column_name [, ...] ) ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
[ GLOBAL/LOCAL ]
    [ TABLESPACE tablespace_name ]
    [ WHERE predicate ]

    非パーティションキーのクエリの高速化

    1. 時間列をパーティションキーとして持つパーティションテーブルを作成できます。

      CREATE TABLE partition_range (
          id INT,
          a INT,
          b INT,
          created_date TIMESTAMP WITHOUT TIME ZONE
      ) PARTITION BY RANGE (created_date);
      
      CREATE TABLE partition_range_part01 PARTITION OF partition_range FOR VALUES FROM (MINVALUE) TO ('2020-01-01 00:00:00');
      CREATE TABLE partition_range_part02 PARTITION OF partition_range FOR VALUES FROM ('2020-01-01 00:00:00') TO ('2020-02-01 00:00:00');
      CREATE TABLE partition_range_part03 PARTITION OF partition_range FOR VALUES FROM ('2020-02-01 00:00:00') TO ('2020-03-01 00:00:00');
    2. 非パーティションキーの条件に基づいてパーティションテーブルをクエリできます。

      EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;

      結果から、すべてのサブパーティションがスキャンされていることがわかります。パーティションプルーニング機能は使用できません。

                              QUERY PLAN
      ------------------------------------------------------------
       Append
         ->  Seq Scan on partition_range_part01 partition_range_1
               Filter: (id = 1)
         ->  Seq Scan on partition_range_part02 partition_range_2
               Filter: (id = 1)
         ->  Seq Scan on partition_range_part03 partition_range_3
               Filter: (id = 1)
      (7 rows)
    3. パーティションテーブルにローカルインデックスを作成し、クエリを再度実行します。

      CREATE INDEX partition_range_idx_local ON partition_range(id);
      
      EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;

      結果から、ローカルインデックスは各サブパーティションに作成されるため、すべてのサブパーティションのローカルインデックスが依然としてスキャンされていることがわかります。

                                                  QUERY PLAN
      --------------------------------------------------------------------------------------------------
       Append
         ->  Index Scan using partition_range_part01_id_idx on partition_range_part01 partition_range_1
               Index Cond: (id = 1)
         ->  Index Scan using partition_range_part02_id_idx on partition_range_part02 partition_range_2
               Index Cond: (id = 1)
         ->  Index Scan using partition_range_part03_id_idx on partition_range_part03 partition_range_3
               Index Cond: (id = 1)
      (7 rows)

    4. GLOBAL キーワードを使用してパーティションテーブルにグローバルインデックスを作成し、クエリを再度実行します。

      CREATE INDEX partition_range_idx_global ON partition_range(id) GLOBAL;
      
      EXPLAIN (COSTS OFF) SELECT * FROM partition_range WHERE id = 1;

      結果から、データベースがグローバルインデックスを使用して、データを含むサブパーティションを直接見つけていることがわかります。

                                    QUERY PLAN
      -----------------------------------------------------------------------
       Global Index Scan using partition_range_idx_global on partition_range
         Index Cond: (id = 1)
      (2 rows)

    非パーティションキーの一意性制約

    前の例と同じパーティションテーブルを使用します。パーティションキーは created_date ですが、一意性制約が必要な列は id です。

    CREATE UNIQUE INDEX partition_range_id_unique_idx ON partition_range(id);
    ERROR:  unique constraint on partitioned table must include all partitioning columns
    DETAIL:  UNIQUE constraint on table "partition_range" lacks column "created_date" which is part of the partition key.
    説明

    ネイティブの PostgreSQL では、ローカルインデックスを使用して非パーティションキーに一意性制約を作成しようとすると、エラーが発生します。エラーメッセージは、パーティションキーがインデックスに含まれている必要があることを示しています。PolarDB for PostgreSQL および は、グローバルインデックス機能を強化しています。デフォルトでは、非パーティションキーの一意性制約は、グローバルインデックスに基づくグローバル制約に変換されます。この動作は polar_pk_in_non_partition_column_mode パラメーターによって制御されます。そのデフォルト値は global_index です。値を none に変更すると、動作はネイティブの PostgreSQL と同じになります。

    ただし、以下に示すように、グローバルインデックスに一意性制約を追加する場合、この制限は適用されません。

    CREATE UNIQUE INDEX partition_range_id_unique_idx ON partition_range(id) GLOBAL;

    パフォーマンステスト

    pgbench を使用してスケールファクター 80000 のデータを生成し、パーティションテーブルと非パーティションテーブルを作成できます。

    非パーティションキーでのポイントクエリのパフォーマンス

    カテゴリ

    TPS

    プリペアドステートメント

    未使用

    使用

    同時実行数

    1

    32

    64

    1

    32

    64

    標準テーブル

    27,732

    494,433

    430,848

    53,935

    985,880

    886,882

    パーティションテーブル + ローカルインデックス

    367

    4,155

    3,688

    856

    8,742

    6,790

    パーティションテーブル + グローバルインデックス

    19,006

    308,128

    262,941

    45,090

    820,924

    731,557

    非パーティションキーでの TPC-B パフォーマンス

    説明

    これには、ポイントクエリとデータ操作言語 (DML) 文が含まれます。

    カテゴリ

    TPS

    プリペアドステートメント

    未使用

    使用

    同時実行数

    1

    32

    64

    1

    32

    64

    標準テーブル

    1,115

    51,025

    60,409

    4,822

    90,312

    100,802

    パーティションテーブル + ローカルインデックス

    271

    2,903

    2,524

    550

    5,276

    4,237

    パーティションテーブル + グローバルインデックス

    非対応

    4,334

    69,040

    75,232

    結論

    グローバルインデックスを使用すると、パーティションテーブルに対するポイントクエリと DML 文のパフォーマンスを桁違いに向上させることができます。