AnalyticDB for PostgreSQL では、テーブル作成時に選択したディストリビューション方式に基づき、テーブルデータをコンピュートノード間で分散します。選択する方式および分散キーは、クラスター全体におけるクエリパフォーマンス、データのバランス、結合効率に直接影響します。
ディストリビューション方式
AnalyticDB for PostgreSQL では、以下の 3 種類のディストリビューション方式をサポートしています。
CREATE TABLE <table_name> (...)
[ DISTRIBUTED BY (<column> [,..] ) | DISTRIBUTED RANDOMLY | DISTRIBUTED REPLICATED ]V4.3 ではハッシュディストリビューションとランダムディストリビューションのみをサポートしています。レプリケーテッドディストリビューションは V6.0 で導入されました。
| 方式 | 構文 | 動作の仕組み | 使用タイミング |
|---|---|---|---|
| ハッシュディストリビューション(デフォルト) | DISTRIBUTED BY (column, [...]) | 各行を分散列のハッシュ値に基づいてコンピュートノードに割り当てます。同じハッシュ値を持つ行は同一ノードに配置されます。DISTRIBUTED 句が指定されていない場合、テーブルはプライマリキーを分散キーとして使用します。適切なキーが存在しない場合は、ランダムディストリビューションにフォールバックします。 | ほとんどのテーブルに使用します。分散キーを用いたクエリでは、コロケーテッド結合およびコンピュートノードのフィルタリングが可能になります。 |
| ランダムディストリビューション | DISTRIBUTED RANDOMLY | ラウンドロビンアルゴリズムを用いて、各行をすべてのコンピュートノードに均等に分散します。同じハッシュ値を持つ行が異なるノードに配置される可能性があります。 | ハッシュディストリビューションに適した列が存在しない場合にのみ使用します。コロケーテッド結合およびコンピュートノードのフィルタリングはサポートされません。 |
| レプリケーテッドディストリビューション | DISTRIBUTED REPLICATED | テーブルの完全なコピーをすべてのコンピュートノードに格納します。 | 頻繁に大規模テーブルと結合される小規模なルックアップテーブルに使用します。結合パフォーマンスを向上させます。 |
例:
-- ハッシュディストリビューション
CREATE TABLE products (
name varchar(40),
prod_id integer,
supplier_id integer
) DISTRIBUTED BY (prod_id);
-- ランダムディストリビューション
CREATE TABLE random_stuff (
things text,
doodads text,
etc text
) DISTRIBUTED RANDOMLY;
-- レプリケーテッドディストリビューション
CREATE TABLE replicated_stuff (
things text,
doodads text,
etc text
) DISTRIBUTED REPLICATED;ハッシュディストリビューションがクエリルーティングに与える影響
クエリが分散キーでフィルター処理を行う場合、AnalyticDB for PostgreSQL は該当する行を保持するコンピュートノードのみにクエリをルーティングします。たとえば、以下のクエリは prod_id = 101 を含むノードにのみ送信され、すべてのノードをスキャンすることはありません。
SELECT * FROM products WHERE prod_id = 101;分散キーの選択
ハッシュディストリビューション向けに効果的な分散キーを選択するには、以下の手順に従ってください。
ステップ 1:データが均等に分散される列を選択します。
データの不均等な分散は「データスキュー」を引き起こし、一部のコンピュートノードに他のノードよりも大幅に多くの行が集中して負荷が増加し、クエリ実行が遅くなる原因となります。カーディナリティが低く、スキューを生じやすいブール値、時刻、日付などの列は避けてください。
ステップ 2:結合条件で頻繁に使用される列を選択します。
結合キーと分散キーが一致する場合、AnalyticDB for PostgreSQL は コロケーテッド結合を実行します。この場合、各コンピュートノードは自身のローカルデータのみを結合し、ノード間でのデータ移動は発生しません。
結合キーと分散キーが異なる場合、クエリエンジンは結合前に リディストリビューションモーションまたは ブロードキャストモーションを実行する必要があります。いずれもコロケーテッド結合に比べてネットワークオーバーヘッドが大きくなります。
![]()
![]()
![]()
ステップ 3:クエリフィルターとして頻繁に使用される列を選択します。
分散キーでフィルター処理を行うと、AnalyticDB for PostgreSQL は関連する行を保持しないコンピュートノードをスキップできるため、クエリごとのスキャン対象データ量を削減できます。
ステップ 4:一意キーを優先します。
プライマリキーなど一意キーはカーディナリティを最大化し、行をノード間で均等に分散させることが保証されます。テーブルにプライマリキーが定義されている場合は、それを起点として検討してください。
ステップ 5:複合分散キーを検討します。
単一の列で上記の要件を満たさない場合、2 つ以上の列を組み合わせて分散キーとします。
CREATE TABLE t1 (c1 int, c2 int) DISTRIBUTED BY (c1, c2);分散キーの使用制限
分散キーの列は更新できません。 分散の再割り当てを行うには、
ALTER TABLE ... SET DISTRIBUTED BYを使用してください。分散キーは、プライマリキーまたは一意キーの一部である必要があります。 以下の例では、分散キー
c2がプライマリキーc1に含まれていないため、実行に失敗します。CREATE TABLE t1 (c1 int, c2 int, PRIMARY KEY (c1)) DISTRIBUTED BY (c2); -- ERROR: PRIMARY KEY and DISTRIBUTED BY definitions incompatibleジオメトリ型およびカスタムデータ型の列は分散キーとして使用できません。
データスキューのトラブルシューティング
データスキューとは、1 つまたは複数のコンピュートノードが他のノードと比較して著しく多くの行を保持する状態です。一般的な原因は、カーディナリティが低い列(たとえば、多数の行が同一値を共有するステータスフラグや日付列)を選択したことによるものです。その値を持つすべての行は同一ノードにハッシュされ、そのノードが過負荷となり、他のノードは未活用のままとなります。
データスキューの検出方法:各コンピュートノードごとの行数をクエリします。
SELECT gp_segment_id, count(1)
FROM t1
GROUP BY 1
ORDER BY 2 DESC;
gp_segment_id | count
---------------+--------
2 | 131191
0 | 72
1 | 68
(3 rows)上記の出力は、ノード 2 がほぼすべてのデータを保持しており、深刻なスキューが発生していることを示しています。
データスキューの修正方法:より均等に分散される値を持つ列に分散キーを変更します。
ALTER TABLE t1 SET DISTRIBUTED BY (c2);再分散後、データはすべてのコンピュートノードに均等に分散されます。