メインコンテンツまでスキップ
バージョン: 3.3

主キーテーブル

StarRocks によって設計された新しいストレージエンジンを使用する主キーテーブルは、リアルタイムデータの更新をサポートしつつ、複雑なアドホッククエリに対して効率的なパフォーマンスを保証します。リアルタイムのビジネス分析において、主キーテーブルは最新のデータを使用して結果をリアルタイムで分析することで、データ分析におけるデータ遅延を軽減することができます。

主キーテーブルの主キーには UNIQUE 制約と NOT NULL 制約があり、各データ行を一意に識別するために使用されます。新しいデータ行の主キー値がテーブル内の既存のデータ行と同じ場合、UNIQUE 制約違反が発生します。その場合、新しいデータ行が既存のデータ行を置き換えます。

備考
  • v3.0 以降、主キーテーブルのソートキーはテーブルの主キーから分離され、ソートキーを別途指定することができます。これにより、テーブル作成の柔軟性が向上しました。
  • v3.1 以降、StarRocks 共有データクラスタは主キーテーブルの作成をサポートしています。
    • v3.1.4 以降、永続性インデックスを ローカルディスク に作成して保存することができます。
    • v3.3.2 以降、永続性インデックスを オブジェクトストレージ に作成して保存することができます。

シナリオ

主キーテーブルはリアルタイムデータの更新をサポートしつつ、効率的なクエリパフォーマンスを保証します。以下のシナリオに適しています:

  • トランザクション処理システムから StarRocks へのリアルタイムデータストリーム。 通常、トランザクション処理システムには大量の更新および削除操作が含まれています。トランザクション処理システムから StarRocks へのデータ同期が必要な場合、主キーテーブルの作成をお勧めします。その後、Apache Flink® の CDC コネクタなどのツールを使用して、トランザクション処理システムのバイナリログを StarRocks に同期できます。StarRocks はバイナリログを使用して、テーブル内のデータをリアルタイムで追加、削除、更新します。これにより、データ同期が簡素化され、Merge-On-Read 戦略を採用したユニークキーテーブルを使用する場合に比べて、3 倍から 10 倍のクエリパフォーマンスが得られます。詳細については、MySQL からのリアルタイム同期を参照してください。
  • 個々の列に対する 部分更新を実行して複数のストリームを結合 します。 ユーザープロファイリングなどのビジネスシナリオでは、フラットテーブルを使用することで多次元分析のパフォーマンスを向上させ、データアナリストが使用する分析モデルを簡素化します。これらのシナリオの上流データは、ショッピングアプリ、配達アプリ、銀行アプリなどのさまざまなアプリや、ユーザーの特定のタグやプロパティを取得するための計算を行う機械学習システムなどから来ることがあります。主キーテーブルは、個々の列の更新をサポートするため、これらのシナリオに適しています。各アプリやシステムは、自身のサービス範囲内のデータを保持する列のみを更新し、リアルタイムのデータ追加、削除、更新の高いクエリパフォーマンスの恩恵を受けることができます。

動作原理

ユニークキーテーブルと集計テーブルは Merge-On-Read 戦略を採用しています。この戦略はデータ書き込みを簡単かつ効率的にしますが、データ読み取り時にオンラインで複数のバージョンのデータファイルをマージする必要があります。さらに、Merge オペレーターが存在するため、述語やインデックスを基礎データにプッシュダウンすることができず、クエリパフォーマンスに大きく影響します。

しかし、リアルタイム更新とクエリのパフォーマンスのバランスを取るために、主キーテーブルのメタデータ構造と読み書きメカニズムは他のタイプのテーブルとは異なります。主キーテーブルは Delete+Insert 戦略を使用します。この戦略は、主キーインデックスと DelVector を使用して実現されます。この戦略により、クエリ中に同じ主キー値を持つレコードの中で最新のレコードのみを読み取る必要があり、複数のバージョンのデータファイルをマージする必要がなくなります。さらに、述語やインデックスを基礎データにプッシュダウンすることができ、クエリパフォーマンスが大幅に向上します。

主キーテーブル内でのデータの書き込みと読み取りの全体的なプロセスは次のとおりです:

  • データ書き込みは、StarRocks の内部 Loadjob を通じて実現され、データ変更操作(Insert、Update、Delete)のバッチが含まれています。StarRocks は対応するタブレットの主キーインデックスをメモリにロードします。Delete 操作の場合、StarRocks はまず主キーインデックスを使用して各データ行の元の位置(データファイルと行番号)を見つけ、DelVector(データロード中に生成された削除マーカーを保存および管理する)でデータ行を削除済みとしてマークします。Update 操作の場合、DelVector で元のデータ行を削除済みとしてマークすることに加えて、StarRocks は最新のデータ行を新しいデータファイルに書き込み、Update を Delete+Insert に変換します(以下の図に示すように)。主キーインデックスも更新され、変更されたデータ行の新しい位置(データファイルと行番号)が記録されます。

    pk1

  • データ読み取り時には、さまざまなデータファイル内の履歴の重複レコードがデータ書き込み時にすでに削除済みとしてマークされているため、同じ主キー値を持つ最新のデータ行のみを読み取る必要があります。複数のバージョンのデータファイルをオンラインで読み取ってデータを重複排除し、最新のデータを見つける必要はありません。基礎データファイルがスキャンされるとき、フィルターオペレーターやさまざまなインデックスがスキャンのオーバーヘッドを削減するのに役立ちます(以下の図に示すように)。したがって、クエリパフォーマンスは大幅に向上します。ユニークキーテーブルの Merge-On-Read 戦略と比較して、主キーテーブルの Delete+Insert 戦略はクエリパフォーマンスを 3 倍から 10 倍向上させることができます。

    pk2

詳細情報

主キーテーブルへのデータの書き込みや読み取りの詳細なプロセスを理解したい場合は、以下の詳細なデータ書き込みおよび読み取りプロセスを参照してください:

StarRocks は列指向(カラムナ)ストレージを使用する分析データベースです。具体的には、テーブル内のタブレットには通常、複数の rowset ファイルが含まれており、各 rowset ファイルのデータは実際にはセグメントファイルに保存されています。セグメントファイルはデータを列指向形式(Parquet に似ている)で整理し、不変です。

書き込まれるデータが Executor BE ノードに分配されると、各 Executor BE ノードは Loadjob を実行します。Loadjob にはデータ変更のバッチが含まれており、ACID 特性を持つトランザクションと見なすことができます。Loadjob は書き込みとコミットの 2 つのステージに分けられます。

  1. 書き込みステージ:データはパーティションとバケット情報に基づいて対応するタブレットに分配されます。タブレットがデータを受け取ると、データは列指向形式で保存され、新しい rowset が形成されます。
  2. コミットステージ:すべてのデータが正常に書き込まれた後、FE は関与するすべてのタブレットにコミットを開始します。各コミットには、タブレットのデータの最新バージョンを表すバージョン番号が含まれています。コミットプロセスには、主キーインデックスの検索と更新、すべての変更されたデータの削除としてのマーク、削除としてマークされたデータに基づく DelVector の作成、新しいバージョンのメタデータの生成が含まれます。

データ読み取り時には、メタデータを使用して最新のタブレットバージョンに基づいて読み取る必要のある rowset を見つけます。rowset 内のセグメントファイルが読み取られるとき、その最新バージョンの DelVector もチェックされ、最新のデータのみを読み取ることができ、同じ主キー値を持つ古いデータを読み取ることを避けることができます。さらに、Scan レイヤーにプッシュダウンされたフィルターオペレーターは、さまざまなインデックスを直接利用してスキャンのオーバーヘッドを削減できます。

  • タブレット:テーブルはパーティションとバケットメカニズムに基づいて複数のタブレットに分割されます。実際の物理ストレージユニットであり、異なる BEs にレプリカとして分散されます。

    pk3

  • メタデータ:メタデータはタブレットのバージョン履歴と各バージョンに関する情報(たとえば、どの rowset が含まれているか)を保存します。各 Loadjob または compaction のコミットフェーズは新しいバージョンを生成します。

    pk4

  • 主キーインデックス:主キーインデックスは、主キー値によって識別されるデータ行とそのデータ行の位置とのマッピングを保存します。HashMap として実装されており、キーはエンコードされた主キー値を表し、値はデータ行の位置(rowset_idsegment_idrowid を含む)を表します。通常、主キーインデックスはデータ書き込み時にのみ使用され、特定の主キー値によって識別される各データ行が存在する rowset と行を見つけるために使用されます。

  • DelVector:DelVector は、各 rowset 内の各セグメントファイル(列指向ファイル)の削除マーカーを保存します。

  • Rowset:rowset は論理的な概念であり、タブレット内のデータ変更のバッチからデータセットを保存します。

  • セグメント:rowset 内のデータは実際にセグメント化され、1 つ以上のセグメントファイル(列指向ファイル)に保存されます。各セグメントファイルには、列の値と列に関連するインデックス情報が含まれています。

使用方法

主キーテーブルの作成

CREATE TABLE ステートメントで主キーを定義するだけで、主キーテーブルを作成できます。例:

CREATE TABLE orders1 (
order_id bigint NOT NULL,
dt date NOT NULL,
user_id INT NOT NULL,
good_id INT NOT NULL,
cnt int NOT NULL,
revenue int NOT NULL
)
PRIMARY KEY (order_id)
DISTRIBUTED BY HASH (order_id)
;
備考

主キーテーブルはハッシュバケッティングのみをバケッティング戦略としてサポートするため、DISTRIBUTED BY HASH () を使用してハッシュバケッティングキーを定義する必要があります。

しかし、実際のビジネスシナリオでは、主キーテーブルを作成する際に、データ分散やソートキーなどの追加機能がクエリを高速化し、データをより効率的に管理するために使用されることがよくあります。

たとえば、注文テーブルの order_id フィールドはデータ行を一意に識別できるため、order_id フィールドを主キーとして使用できます。

v3.0 以降、主キーテーブルのソートキーはテーブルの主キーから分離されています。したがって、クエリフィルター条件として頻繁に使用される列を選択してソートキーを形成することができます。たとえば、注文日と商人の 2 つの次元の組み合わせに基づいて製品の販売パフォーマンスを頻繁にクエリする場合、ORDER BY (dt,merchant_id) 句を使用してソートキーを dtmerchant_id に指定できます。

データ分散戦略を使用する場合、主キーテーブルは現在、パーティション列とバケッティング列を主キーに含める必要があります。たとえば、データ分散戦略は dt をパーティション列として使用し、merchant_id をハッシュバケッティング列として使用します。主キーには dtmerchant_id も含める必要があります。

要約すると、上記の注文テーブルの CREATE TABLE ステートメントは次のようになります:

CREATE TABLE orders2 (
order_id bigint NOT NULL,
dt date NOT NULL,
merchant_id int NOT NULL,
user_id int NOT NULL,
good_id int NOT NULL,
good_name string NOT NULL,
price int NOT NULL,
cnt int NOT NULL,
revenue int NOT NULL,
state tinyint NOT NULL
)
PRIMARY KEY (order_id,dt,merchant_id)
PARTITION BY date_trunc('day', dt)
DISTRIBUTED BY HASH (merchant_id)
ORDER BY (dt,merchant_id)
PROPERTIES (
"enable_persistent_index" = "true"
);

主キー

テーブルの主キーは、そのテーブル内の各行を一意に識別するために使用されます。主キーを構成する 1 つ以上の列は PRIMARY KEY で定義され、UNIQUE 制約と NOT NULL 制約があります。

主キーに関する考慮事項は次のとおりです:

  • CREATE TABLE ステートメントでは、主キー列は他の列の前に定義する必要があります。
  • 主キー列にはパーティション列とバケッティング列を含める必要があります。
  • 主キー列は、数値型(整数および BOOLEAN を含む)、文字列型、日付型(DATE および DATETIME)をサポートします。
  • デフォルトでは、エンコードされた主キー値の最大長は 128 バイトです。
  • 主キーはテーブル作成後に変更できません。
  • データの一貫性を保つために、主キー値は更新できません。

主キーインデックス

主キーインデックスは、主キー値と主キー値によって識別されるデータ行の位置とのマッピングを保存するために使用されます。通常、関連するタブレットの主キーインデックスはデータロード中(データ変更のバッチが含まれる)にのみメモリにロードされます。クエリと更新のパフォーマンス要件、およびメモリとディスクを包括的に評価した上で、主キーインデックスを永続化することを検討できます。

enable_persistent_indextrue(デフォルト)に設定されている場合、主キーインデックスはディスクに永続化されます。ロード中、主キーインデックスの一部はメモリにロードされ、大部分はディスクに保存され、メモリを過剰に占有しないようにします。一般的に、永続性のある主キーインデックスを持つテーブルのクエリおよび更新パフォーマンスは、完全にメモリ内の主キーインデックスを持つテーブルとほぼ同等です。

ディスクが SSD の場合、true に設定することをお勧めします。ディスクが HDD でロード頻度が高くない場合も、true に設定できます。

v3.1.4 以降、StarRocks 共有データクラスタで作成された主キーテーブルはローカルディスクへのインデックスの永続化をサポートしています。そして、v3.3.2 以降、StarRocks 共有データクラスタはさらにオブジェクトストレージへのインデックスの永続化をサポートしています。この機能を有効にするには、テーブルプロパティ persistent_index_typeCLOUD_NATIVE に設定します。

ソートキー

v3.0 以降、主キーテーブルはソートキーを主キーから分離しています。ソートキーは ORDER BY で定義された列で構成され、列のデータ型がソートキーの要件を満たす限り、任意の列の組み合わせで構成できます。

データロード中、データはソートキーに従ってソートされた後に保存されます。ソートキーはクエリアクセラレーションのためにプレフィックスインデックスを構築するためにも使用されます。クエリアクセラレーションを実現するプレフィックスインデックスを形成するためにソートキーを適切に設計することをお勧めします

備考
  • ソートキーが指定されている場合、プレフィックスインデックスはソートキーに基づいて構築されます。ソートキーが指定されていない場合、プレフィックスインデックスは主キーに基づいて構築されます。
  • テーブル作成後、ALTER TABLE ... ORDER BY ... を使用してソートキーを変更できます。ソートキーの削除はサポートされておらず、ソート列のデータ型の変更もサポートされていません。

その他

  • 作成されたテーブルにデータをロードするには、Loading overview を参照して適切なロードオプションを選択できます。
  • 主キーテーブルのデータを変更する必要がある場合は、change data through loading を参照するか、DML(INSERTUPDATE、および DELETE)を使用できます。
  • クエリをさらに高速化する必要がある場合は、Query Acceleration を参照できます。
  • テーブルスキーマを変更する必要がある場合は、ALTER TABLE を参照できます。
  • AUTO_INCREMENT 列を主キーとして使用できます。
Rocky the happy otterStarRocks Assistant

AI generated answers are based on docs and other sources. Please test answers in non-production environments.