PolarDB-X の分散テーブルにおいて、パーティションキーを含まないクエリはすべてのデータノードに対してフルスキャンをトリガーします。これによりパフォーマンスがシングルノードの上限にまで低下し、線形スケーリングが失われます。グローバルセカンダリインデックス (GSI) を使用すると、インデックスに対して独立したパーティションスキームを定義できるため、任意の列を効率的なクエリパスにできます。その結果、フルパーティションスキャンを回避できます。
GSI の仕組み
PolarDB-X は、指定されたキーでパーティション分割された複数のデータノードにテーブルデータを格納します。パーティションキーを含むクエリは、該当するパーティションに直接ルートされます。一方、パーティションキーを含まないクエリはすべてのパーティションに分散されます。
システムに N 個のデータノードがある場合、パーティションキーを使用したクエリは各ノードに平均して 1/N の負荷をかけます。一方、フルパーティションスキャンでは各ノードに負荷 1 がかかります。そのため、パフォーマンスの上限がシングルノードレベルまで低下し、システムは線形スケーリング能力を失います。
GSI は、プライマリテーブルから特定の列を複製した特殊なパーティションテーブルとして機能することでこの問題を解決します。GSI は、プライマリテーブルのパーティションキーとは異なるユーザー定義キーによって水平方向にパーティション分割されます。クエリが GSI のパーティションキーと一致する場合、PolarDB-X はそのクエリを該当する GSI パーティションにルートし、一致する行を取得した後、プライマリテーブルから追加の必要な列をフェッチします。これにより、フルパーティションスキャンを回避できます。
PolarDB-X は、分散トランザクションを使用して、プライマリテーブルとその GSI 間の強固なデータ整合性を維持します。
GSI は以下の機能もサポートしています。
オンライン DDL 操作 — テーブルをロックせずに GSI を作成・変更・削除可能
カスタムカバリングカラム — GSI 内に追加の列を格納することで、プライマリテーブルへのルックアップを削減または完全に排除可能
非表示インデックス — クエリオプティマイザーに公開せずにクエリプランへの影響をテスト可能。本番環境で有効化する前にインデックスのパフォーマンスを検証できます
GSI の種類
GSI
標準的な GSI は、プライマリテーブルのパーティションキー以外の列でインデックスデータをパーティション分割します。クエリが GSI のパーティションキーと一致する場合、PolarDB-X はそのクエリを該当するパーティションにルートし、残りの列についてはプライマリテーブルを参照します。
例: user テーブルは user_id でパーティション分割されています。name による効率的なクエリをサポートするために、name 上に GSI を作成します。
CREATE TABLE user(
user_id bigint,
name varchar(10),
addr varchar(30),
GLOBAL INDEX `g_i_name` (name) PARTITION BY HASH(name),
PRIMARY KEY(user_id)
) PARTITION BY KEY(user_id);g_i_name が存在する場合、name でフィルターするクエリは user テーブルのすべてのパーティションをスキャンするのではなく、インデックスの該当するパーティションにルートされます。
UGSI
ユニークグローバルセカンダリインデックス (UGSI) は、標準 GSI のすべてのプロパティに加えて、分散テーブル全体にわたってグローバルな UNIQUE 制約を適用します。
例: user2 テーブルは user_id でパーティション分割されています。すべてのパーティションにわたって phone の一意性を保証するために、phone 上に UGSI を作成します。
CREATE TABLE user2(
user_id bigint,
phone varchar(20),
addr varchar(30),
UNIQUE GLOBAL INDEX `g_i_phone`(phone) PARTITION BY HASH(phone),
PRIMARY KEY(user_id)
) PARTITION BY KEY(user_id);クラスタード GSI
デフォルトでは、クラスタード GSI はインデックスキーおよびカバリングカラムだけでなく、プライマリテーブルのすべての列を格納します。すべての列がインデックス内に存在するため、クエリはプライマリテーブルを参照する必要がなくなり、ルックアップオーバーヘッドが完全に排除されます。
トレードオフとして、クラスタード GSI はプライマリテーブルと同じ量のディスク領域を消費します。
例: order_tbl テーブルは order_id でパーティション分割されています。プライマリテーブルへのルックアップなしで user_id による高速クエリをサポートするために、user_id 上にクラスタード GSI を作成します。
CREATE TABLE order_tbl(
order_id bigint,
user_id bigint,
addr varchar(30),
info text,
create_time datetime,
CLUSTERED INDEX `cg_i_user`(user_id) PARTITION BY HASH(user_id),
PRIMARY KEY(order_id)
) PARTITION BY KEY(order_id);user_id でクエリを実行する際、PolarDB-X はクエリを cg_i_user の該当するパーティションにルートし、必要なすべてのデータをインデックスから直接読み取ります。
各タイプの使用タイミング
| シナリオ | 推奨タイプ |
|---|---|
| パーティションキー以外の列でクエリを実行し、プライマリテーブルへのルックアップが許容される場合 | GSI |
| パーティションキー以外の列でクエリを実行し、その列が全パーティションで一意である必要がある場合 | UGSI |
| パーティションキー以外の列でクエリを実行し、ルックアップオーバーヘッドの排除が優先度の高い場合 | クラスタード GSI |
パフォーマンス
GSI は読み取りパフォーマンスを向上させる一方で、書き込みパフォーマンスを低下させます。以下の Sysbench ベンチマークは、スケール時の影響を示しています。
読み取りパフォーマンス
| テーブル | スレッド数 | select_random_ranges QPS | 平均遅延時間 (ms) | 95 パーセンタイル (ms) | select_random_points QPS | 平均遅延時間 (ms) | 95 パーセンタイル (ms) |
|---|---|---|---|---|---|---|---|
| パーティションテーブル | 128 | 2,769.17 | 46.21 | 99.33 | 5,226.99 | 24.48 | 42.61 |
| 256 | 3,415.64 | 144.97 | 144.97 | 5,476.76 | 46.73 | 82.96 | |
| 512 | 3,272.46 | 156.31 | 257.95 | 5,290.67 | 96.72 | 179.94 | |
| 1024 | 2,453.16 | 416.12 | 539.71 | 5,165.31 | 198.07 | 404.61 | |
| パーティションテーブル + GSI | 128 | 9,662.11 | 13.24 | 25.28 | 22,584.89 | 5.66 | 9.73 |
| 256 | 10,431.73 | 24.52 | 51.02 | 25,558.26 | 10.01 | 17.95 | |
| 512 | 15,634.51 | 32.72 | 73.13 | 27,116.56 | 18.86 | 39.65 | |
| 1024 | 22,948.76 | 44.53 | 108.68 | 32,509.87 | 31.43 | 73.13 |
インデックスキー列に GSI を設定した場合:
範囲クエリ QPS:3,415.64 → 22,948.76 — 571 % 向上
ポイントクエリ QPS:5,476.76 → 32,509.87 — 493 % 向上
書き込みパフォーマンス
| テーブル | スレッド数 | 書き込み専用 QPS | 平均遅延時間 (ms) | 95 パーセンタイル (ms) | 読み書き混在 QPS | 平均遅延時間 (ms) | 95 パーセンタイル (ms) |
|---|---|---|---|---|---|---|---|
| パーティションテーブル | 128 | 86,548.12 | 8.87 | 10.27 | 113,655.28 | 22.52 | 26.2 |
| 256 | 115,774.71 | 13.26 | 19.29 | 149,677.52 | 34.19 | 44.17 | |
| 512 | 143,928.94 | 20.51 | 34.95 | 14,555.16 | 70.28 | 112.67 | |
| 1024 | 153,501.7 | 39.53 | 70.55 | 132,150.69 | 131.58 | 287.38 | |
| パーティションテーブル + GSI | 128 | 52,069.22 | 14.25 | 18.28 | 90,074.59 | 28.41 | 33.72 |
| 256 | 66,250.79 | 23.17 | 32.53 | 114,420.32 | 44.73 | 57.87 | |
| 512 | 75,700.74 | 39.1 | 59.99 | 111,093.61 | 92.09 | 142.39 | |
| 1024 | 76,557.94 | 80.14 | 134.9 | 101,828.32 | 182.51 | 350.33 |
インデックスキー列に GSI を設定した場合:
書き込み専用 QPS:153,501.7 → 76,557.94 — 50 % 低下
読み書き混在 QPS:149,677.52 → 114,420.32 — 23 % 低下