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

PolarDB:グローバルセカンダリインデックスの使用

最終更新日:Mar 29, 2026

シャード化されたデータベースでは、データがシャードキーに基づいて物理シャードに分散されます。シャードキー以外の列をフィルター条件としてクエリを実行すると、PolarDB-X はすべてのシャードをスキャンする必要があります。これは、データ量の増加に伴いコストが増大するフルシャードスキャンです。グローバルセカンダリインデックス(GSI)は、インデックス対象列をシャードキーとして独立してシャード化された別個のインデックステーブルを維持することでこの課題を解決します。これにより、オプティマイザーはクエリを関連するシャードに直接ルーティングできます。

本トピックでは、PolarDB-X で GSI を作成し、クエリの高速化に活用する方法について説明します。

前提条件

開始する前に、以下の条件を満たしていることを確認してください。

  • MySQL 5.7 以降

  • PolarDB-X カーネルのマイナーバージョン 5.4.1 以降

グローバルセカンダリインデックスの仕組み

GSI は、以下のコンポーネントで構成されます。

コンポーネント説明
インデックステーブルGSI 用に作成される別個の分散テーブルであり、インデックス対象列をシャードキーとしてプライマリテーブルとは独立してシャード化されます。
インデックスキー列インデックステーブルのシャードキーです。シャーディング句で参照されるすべての列がインデックスキー列になります。
カバリング列インデックスキー列に加えて、インデックステーブルに格納される追加の列です。デフォルトでは、プライマリテーブルのプライマリキーおよびすべてのシャードキーが含まれます。クエリで必要な列がすべてインデックステーブルに存在する場合、PolarDB-X はプライマリテーブルへの参照を経ずにインデックステーブルから直接読み取りを行います。これをカバリングインデックス読み取りと呼びます。
シャーディング句インデックステーブルをデータベースおよびテーブルパーティションにどのように分散するかを指定します。CREATE TABLE のシャーディング句と同じ構文を使用します。

GSI を使用するタイミング:クエリが頻繁にプライマリテーブルのシャードキー以外の列をフィルター条件として使用しており、フルシャードスキャンによってパフォーマンスが低下している場合に GSI を作成します。ほとんどのクエリがシャードキーを直接使用する場合は、GSI を導入してもストレージおよび書き込みのオーバーヘッドのみが発生し、パフォーマンス向上の効果は得られません。

GSI の作成

PolarDB-X は、MySQL のデータ定義言語(DDL)構文を拡張し、GSI の定義をサポートしています。その構文は、標準的な MySQL インデックス作成と同様のパターンに従います。

GSI を追加する方法は、以下の 2 通りがあります。

  • テーブル作成時に GSI をインラインで定義する

  • 既存のテーブルに CREATE GLOBAL INDEX を使用して GSI を追加する

以下の例では、t_order テーブルを order_id でシャード化したケースを想定しています。このテーブルには、クエリで頻繁にフィルター条件として使用される buyer_id および seller_id 列も存在し、これらは GSI の適切な候補となります。

-- テーブル作成時に GSI を定義
CREATE TABLE t_order (
  `id` bigint(11) NOT NULL AUTO_INCREMENT,
  `order_id` varchar(20) DEFAULT NULL,
  `buyer_id` varchar(20) DEFAULT NULL,
  `seller_id` varchar(20) DEFAULT NULL,
  `order_snapshot` longtext DEFAULT NULL,
  `order_detail` longtext DEFAULT NULL,
  PRIMARY KEY (`id`),
  GLOBAL INDEX `g_i_seller`(`seller_id`) COVERING (`id`, `order_id`, `buyer_id`, `order_snapshot`) dbpartition by hash(`seller_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 dbpartition by hash(`order_id`);

-- 既存のテーブルに GSI を追加
CREATE UNIQUE GLOBAL INDEX `g_i_buyer` ON `t_order`(`buyer_id`)
    COVERING(`seller_id`, `order_snapshot`)
    dbpartition by hash(`buyer_id`) tbpartition by hash(`buyer_id`) tbpartitions 3

GSI の完全な作成構文およびオプションの詳細については、「CREATE INDEX」をご参照ください。

GSI の使用

GSI を作成した後、クエリでは以下の 3 つの方法で利用できます:オプティマイザーによる自動選択、明示的な HINT 構文の使用、またはインデックステーブルへの直接クエリ実行です。

自動インデックス選択

プライマリテーブルに対するクエリで一致する GSI が存在する場合、PolarDB-X はコストが最も低いインデックスを自動的に選択します。ただし、自動選択の対象となるのはカバリングインデックスのみです。インデックステーブルにクエリで必要なすべての列が含まれていない場合、オプティマイザーはそのインデックスを自動的に選択しません。

以下の例では、クエリが seller_id をフィルター条件として使用し、id および order_snapshot を選択しています。このとき、g_i_seller はこれらの 3 つの列をすべてカバーしており、かつ seller_id がそのシャードキーであるため、オプティマイザーはクエリをインデックステーブルに直接ルーティングし、t_order のプライマリシャードに対するフルスキャンを回避します。

EXPLAIN SELECT t_order.id, t_order.order_snapshot FROM t_order WHERE t_order.seller_id = 's1';
IndexScan(tables="g_i_seller_sfL1_2", sql="SELECT `id`, `order_snapshot` FROM `g_i_seller` AS `g_i_seller` WHERE (`seller_id` = ?)")

HINT を使用したインデックス指定

インデックスヒントを使用すると、オプティマイザーの選択をオーバーライドできます。PolarDB-X では、以下の 2 種類の HINT 構文をサポートしています。

`FORCE INDEX` — 指定された名前のインデックスを強制的に使用します。

SELECT a.*, b.order_id
  FROM t_seller a
    JOIN t_order b FORCE INDEX(g_i_seller) ON a.seller_id = b.seller_id
  WHERE a.seller_nick = "abc";

TDDL ヒント — コメント形式のディレクティブでインデックスを指定します。

/*+TDDL:INDEX({table_name/table_alias}, {index_name})*/

例:

/*+TDDL:index(a, g_i_buyer)*/ SELECT * FROM t_order a WHERE a.buyer_id = 123
クエリでインデックステーブルに格納されていない列が必要な場合、PolarDB-X は 2 段階の検索を実行します。まずインデックステーブルをクエリしてプライマリキーおよびプライマリテーブルのシャードキーを取得し、次にそれらを基にプライマリテーブルをクエリして残りの列を取得します。詳細については、「INDEX HINT」をご参照ください。

インデックステーブルへの直接クエリ

クエリで必要なすべての列がインデックステーブルに含まれている場合、プライマリテーブルを介さず、インデックステーブルに対して直接クエリを実行して結果を取得できます。

USE INDEX および IGNORE INDEX によるインデックス選択制御

USE INDEX を使用すると、オプティマイザーの検討対象を特定のインデックスセットに制限できます。また、IGNORE INDEX を使用すると、指定したインデックスを検討対象から除外できます。

-- g_i_seller の使用を禁止
SELECT t_order.id, t_order.order_snapshot FROM t_order IGNORE INDEX(g_i_seller) WHERE t_order.seller_id = 's1';

-- オプティマイザーが g_i_seller のみを検討するよう制限
SELECT t_order.id, t_order.order_snapshot FROM t_order USE INDEX(g_i_seller) WHERE t_order.seller_id = 's1';

どちらの構文でも、カンマ区切りのインデックス名リストを指定できます:IGNORE INDEX(index1, index2, ...)

次のステップ

  • CREATE INDEX — GSI 作成の完全な構文リファレンス

  • INDEX HINT — インデックスヒントの構文および動作に関する詳細ガイド