ビジネスの成長に伴い、単一テーブルのパフォーマンスと容量がボトルネックになる可能性があります。従来のソリューションは、単一サーバーのハードウェアをアップグレードする垂直スケーリング (スケールアップ) です。しかし、このアプローチは、費用対効果と物理的な容量の点で、すぐに限界に達します。水平スケーリング (スケールアウト) は、複数のサーバーにデータを分散させることで、よりスケーラブルなソリューションを提供します。PolarDB for PostgreSQL (Distributed) クラスターは水平スケーリングを使用し、データ分布を管理するために 2 種類の特別なテーブルタイプを導入しています。大規模なデータセット用の分散テーブルと、頻繁に結合される小規模なデータセット用のレプリケートされたテーブルです。このトピックでは、これら 2 種類のテーブルの作成と管理について説明します。
分散テーブルの作成
分散テーブルの作成は、水平データ分割における中心的なステップです。ユーザーテーブルや注文詳細テーブルなど、大量のデータを格納するビジネス テーブルに適しています。これは 2 ステップのプロセスです。まず、標準テーブルを作成します。次に、create_distributed_table 関数を使用して分散テーブルに変換します。
1. 分布列の選択
分布列は、データが異なるデータノード (DN) にどのように分散されるかを決定するためのキーです。システムは、指定された列のハッシュ値を使用してデータ行をルーティングします。
選択の原則: テーブルのプライマリキーまたは一意の識別子を分布列として選択します。これにより、データが均等に分散されることが保証されます。
重要な制限事項: テーブルにプライマリキーまたは一意制約がある場合、分布列は制約を構成する列のいずれかである必要があります。
例: 標準テーブル t を分散テーブルに変換し、id 列を分布列として使用します。
tという名前の標準テーブルを作成します。CREATE TABLE t (id int primary key, data text);分散テーブルに変換し、
id列を分布列として使用します。SELECT create_distributed_table('t', 'id');次の結果が返されます。
create_distributed_table -------------------------- (1 row)
2. (オプション) シャード数の指定
シャードは、分散テーブルの物理的なストレージユニットです。デフォルトでは、各分散テーブルは 32 個のシャードで作成されます。テーブル作成時にシャード数を明示的に指定することも、polar_cluster.shard_count パラメーターを使用してグローバルに設定することもできます。
例: 4 つのシャードを持つ分散テーブルを作成します。
t1という名前の標準テーブルを作成します。CREATE TABLE t1 (id int primary key, data text);シャード数を明示的に指定します。
shard_countパラメーターの使用shard_countパラメーターを使用して、変換中にシャード数を指定します。SELECT create_distributed_table('t1', 'id', shard_count := 4);次の結果が返されます。
create_distributed_table -------------------------- (1 row)シャード数をクエリします。
SELECT * FROM pg_dist_shard WHERE logicalrelid = 't1'::regclass;次の結果が返されます。
logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------+---------+--------------+---------------+--------------- t1 | 102072 | t | -2147483648 | -1073741825 t1 | 102073 | t | -1073741824 | -1 t1 | 102074 | t | 0 | 1073741823 t1 | 102075 | t | 1073741824 | 2147483647 (4 rows)
polar_cluster.shard_countパラメーターの使用polar_cluster.shard_countパラメーターを使用して、シャード数をグローバルに設定します。SET polar_cluster.shard_count TO 4;テーブルを分散テーブルに変換します。
SELECT create_distributed_table('t1', 'id');次の結果が返されます。
create_distributed_table -------------------------- (1 row)シャード数をクエリします。
SELECT * FROM pg_dist_shard WHERE logicalrelid = 't1'::regclass;次の結果が返されます。
logicalrelid | shardid | shardstorage | shardminvalue | shardmaxvalue --------------+---------+--------------+---------------+--------------- t1 | 102072 | t | -2147483648 | -1073741825 t1 | 102073 | t | -1073741824 | -1 t1 | 102074 | t | 0 | 1073741823 t1 | 102075 | t | 1073741824 | 2147483647 (4 rows)
3. (オプション) コロケーショングループを使用した JOIN パフォーマンスの最適化
多くのビジネスアプリケーションでは、単一のエンティティに関する情報が複数のテーブルにまたがって格納されることがよくあります。関連するすべての情報を取得するには、JOIN クエリが必要です。たとえば、user_info テーブルにはすべてのユーザーデータが格納され、user_order テーブルにはすべてのユーザーの注文が格納されます。これら 2 つのテーブルは、user_id で結合する必要があります。
分散データベースでは、これらのテーブルのデータが異なるノードに分散している場合、結合クエリはノード間のデータ転送をトリガーします。これにより、高いオーバーヘッドが発生します。この問題に対処するために、PolarDB for PostgreSQL (Distributed) はコロケーショングループの概念を導入しています。
機能: 複数のテーブルから同じ分散キー値を持つ行が、物理的に同じデータノードに格納されることを保証します。たとえば、
user_idが 1001 であるすべての関連レコードが一緒に保持されます。これにより、分散キーに対するJOIN操作を単一ノードで効率的に実行でき、ローカルクエリに匹敵するパフォーマンスを提供します。使用方法: PolarDB for PostgreSQL (Distributed) は、コロケーショングループを管理する 2 つの方法を提供します。暗黙的な方法 (デフォルトの動作) と明示的な方法 (推奨される方法) です。
デフォルトのコロケーション (暗黙的な動作):
colocate_withパラメーターを指定せずに分散テーブルを作成すると、システムは自動的にデフォルトのコロケーショングループに配置します。このグループ化は、分布列の型とシャード数という 2 つのプロパティに基づいています。これは、同じ分布列の型とシャード数を持つテーブルが、デフォルトでコロケーションされていると見なされることを意味します。説明デフォルトのコロケーション (暗黙的な動作): 2 つの分散テーブルが同じ分布列のデータ型とシャード数を持っていても、それらのデータが必ずしも関連しているとは限りません。
明示的な制御 (推奨される方法): デフォルトの動作では、関連のないビジネス テーブルが誤ってグループ化されてしまう可能性があります。テーブルのコロケーションを正確に制御するには、関係を明示的に宣言します。
コロケーショングループの最初のテーブルを作成するときは、
create_distributed_table関数でcolocate_with := 'none'を設定します。これにより、テーブル用に新しい独立したコロケーショングループが作成されます。コロケーションする必要がある後続のテーブルを作成するときは、
colocate_with := 'first_table_name'を設定して、既存のコロケーショングループに追加します。
例: ユーザーテーブルと注文テーブルを 1 つのコロケーショングループに配置し、動物関連のテーブルを別のコロケーショングループに配置します。
ユーザーと注文に関連するテーブルを作成し、同じコロケーショングループに配置します。
-- 新しいコロケーショングループを作成 CREATE TABLE user_info (user_id int, user_data text); SELECT create_distributed_table('user_info', 'user_id', colocate_with := 'none'); -- 既存のコロケーショングループに追加 CREATE TABLE user_order (user_id int, order_id int, order_data text); SELECT create_distributed_table('user_order', 'user_id', colocate_with := 'user_info');動物関連のテーブルを作成し、別のコロケーショングループに配置します。
-- 新しいコロケーショングループを作成 CREATE TABLE animal (animal_id int, animal_data text); SELECT create_distributed_table('animal', 'animal_id', colocate_with := 'none'); -- 既存のコロケーショングループに追加 CREATE TABLE animal_class (animal_id int, class_id int, class_data text); SELECT create_distributed_table('animal_class', 'animal_id', colocate_with := 'animal');2 つの分散テーブルのグループが異なるコロケーション ID を持っていることを確認します。これにより、それらが別々のコロケーショングループに追加されたことが確認されます。
SELECT table_name, colocation_id, polar_cluster_table_type, distribution_column, shard_count FROM polar_cluster_tables WHERE table_name IN ( 'user_info'::regclass, 'user_order'::regclass, 'animal'::regclass, 'animal_class'::regclass) ORDER BY colocation_id;次の結果が返されます。
table_name | colocation_id | polar_cluster_table_type | distribution_column | shard_count --------------+---------------+--------------------------+---------------------+------------- user_info | 3 | distributed | user_id | 4 user_order | 3 | distributed | user_id | 4 animal | 4 | distributed | animal_id | 4 animal_class | 4 | distributed | animal_id | 4 (4 rows)
レプリケートされたテーブルの作成
レプリケートされたテーブル (参照テーブルとも呼ばれます) は、そのデータの完全なコピーをすべてのデータノードに格納します。国別コードや製品カテゴリなど、分散テーブルと頻繁に結合される少量の公開データやディメンションテーブルの格納に適しています。
利点: ノード間のクエリを回避し、結合操作を高速化します。
コスト: 書き込み操作はすべてのノードで同期されるため、高いオーバーヘッドが発生します。このため、レプリケートされたテーブルは、頻繁に変更されるデータには適していません。
例: レプリケートされたテーブルを作成します。
t_referenceという名前の標準テーブルを作成します。CREATE TABLE t_reference (id int primary key, data text);レプリケートされたテーブルに変換します。この操作では、テーブル名を指定するだけで済みます。
SELECT create_reference_table('t_reference');次の結果が返されます。
create_reference_table ------------------------ (1 row)レプリケートされたテーブルの情報をクエリします。出力は、レプリケートされたテーブルがすべてのノードに同じ名前のシャードを持っていることを示しています。
SELECT table_name, polar_cluster_table_type, distribution_column, shard_count FROM polar_cluster_tables WHERE table_name = 't_reference'::regclass;次の結果が返されます。
table_name | polar_cluster_table_type | distribution_column | shard_count -------------+--------------------------+---------------------+------------- t_reference | reference | <none> | 1 (1 row)SELECT table_name, shardid, nodename, nodeport FROM polar_cluster_shards WHERE table_name = 't_reference'::regclass;次の結果が返されます。
table_name | shardid | nodename | nodeport -------------+---------+----------------+---------- t_reference | 102096 | 10.xxx.xxx.xxx | 3007 t_reference | 102096 | 10.xxx.xxx.xxx | 3020 t_reference | 102096 | 10.xxx.xxx.xxx | 3006 t_reference | 102096 | 10.xxx.xxx.xxx | 3003 (4 rows)
分散テーブルの管理
分散テーブルを標準テーブルに戻す
分散機能が不要になった場合は、undistribute_table 関数を使用して、分散テーブルまたはレプリケートされたテーブルを標準テーブルに戻すことができます。データはすべてのシャードから自動的に収集され、プライマリコーディネーターノード (CN) に移動されます。
例: 分散テーブル t を標準テーブルに戻します。
SELECT undistribute_table('t');次の結果が返されます。
NOTICE: creating a new table for public.t
NOTICE: moving the data of public.t
NOTICE: dropping the old public.t
NOTICE: renaming the new table to public.t
undistribute_table
--------------------
(1 row)その他の DDL 操作
既存の分散テーブルに対しては、標準の PostgreSQL テーブルと同様に、他のデータ定義言語 (DDL) 操作を実行できます。これらの操作は、論理テーブルと物理テーブルの構造の一貫性を保つために、すべての物理シャードに自動的に伝播されます。
テーブルの削除:
DROP TABLE table_name;インデックスの作成:
CREATE INDEX index_name ON table_name (column_name);