AUTO INCREMENT と グローバル辞書 を使用した COUNT(DISTINCT) と ジョイン の高速化
このトピックでは、AUTO INCREMENT 列とグローバル辞書を使用して COUNT(DISTINCT) 計算とジョインを高速化する方法について説明します。
ユースケース
-
シナリオ 1: 大量のデータ(小売や配送注文など)に対して正確な重複排除を行う必要があるとします。しかし、重複排除のための列が STRING 型であるため、カウント時にパフォーマンスが最適でない可能性があります。例えば、
orders
テーブルのorder_uuid
列は STRING 型で、通常 32 から 36 バイトのサイズで、UUID()
や類似の関数によって生成されます。この場合、order_uuid
の STRING 列に対する COUNT(DISTINCT) クエリSELECT count(DISTINCT order_uuid) FROM orders WHERE create_date >= CURDATE();
は満足のいくパフォーマンスを提供しないかもしれません。正確な重複排除のために INTEGER 列を使用すると、パフォーマンスが大幅に向上します。 -
シナリオ 2: ビットマップ関数を使用して多次元分析における正確な重複排除を高速化したい とします。
bitmap_count()
関数は INTEGER 入力を必要としますが、重複排除する列が STRING 型の場合、bitmap_hash()
関数を使用する必要があります。これにより、重複排除のカウントが近似的でやや低くなる可能性があり、クエリパフォーマンスが低下し、ストレージ要件が増加する可能性があります。これは、bitmap_hash() によって生成された INTEGER 値が、順次割り当てられた INTEGER 値と比較してより分散しているためです。 -
シナリオ 3: 注文の発注と支払いの間の短い時間間隔での注文数をクエリする必要があるとします。注文の発注時間と支払い時間は、異なるビジネスチームによって管理される異なるテーブルに保存されているかもしれません。これらのテーブルを注文 ID に基づいてジョインし、注文を重複排除する必要があるかもしれません。例えば:
SELECT count(distinct order_uuid)
FROM orders_t1 as t1 JOIN orders_t2 as t2
ON t1.order_uuid = t2.order_uuid
WHERE t2.payment_time - t1.create_time <= 3600
AND create_date >= CURDATE();しかし、ジョインに STRING 型の
order_uuid
列を使用することは、INTEGER 列を使用するよりも効率が悪いです。
最適化アプローチ
上記のシナリオの問題に対処するための最適化アプローチは、注文データをターゲットテーブルにロードし、STRING 値と INTEGER 値の間にマッピングを確立することです。その後のクエリ分析は INTEGER 列に基づいて行われます。このアプローチは以下の段階に分けられます。
-
ステージ 1: グローバル辞書を作成し、STRING 値と INTEGER 値の間にマッピングを確立します。この辞書では、キー列は STRING 型で、値列は AUTO INCREMENT INTEGER 型です。データがロードされると、システムは各 STRING 値に一意の ID を自動的に生成し、STRING 値と INTEGER 値の間にマッピングを作成します。
-
ステージ 2: 注文データとグローバル辞書の間のマッピング関係をターゲットテーブルにロードします。
-
ステージ 3: その後のクエリ分析で、ターゲットテーブルの INTEGER 列を使用して正確な重複排除やジョインを行い、パフォーマンスを大幅に向上させます。
-
ステージ 4: さらなるパフォーマンスの最適化のために、INTEGER 列にビットマップ関数を使用して正確な重複排除を高速化することができます。
ソリューション
v3.2.5 以前では、ステージ 2 は次の 2 つの方法で実装できました。
- 外部テーブルまたは内部テーブルを中間テーブルとして使用し、ロード前に辞書テーブルとジョインして対応する辞書 ID を取得します。
- 主キーテーブルを使用してデータロードを行い、その後、ジョイン操作を伴う UPDATE 文を使用して辞書 ID を更新します。しかし、このデータロードプロセスは不便で、多くの制約があります。
v3.2.5 以降、StarRocks は dict_mapping()
関数を導入し、ターゲットテーブルの辞書 ID 列を dict_mapping()
式を使用して生成列として定義できるようになりました。その後のデータロードタスクは通常のデータロードのように処理され、辞書 ID を書き込むためにジョイン操作を伴う UPDATE 文を必要としません。データロード中に、システムは元のテーブルを辞書テーブルと自動的に関連付け、対応する辞書 ID を挿入します。これにより、テーブルタイプに関係なく、さまざまなロード 方法をサポートし、グローバル辞書テーブルを使用したデータロードプロセスが大幅に簡素化されます。
ビジネスシナリオ
以下の例では、id
と order_uuid
の 2 列を含む 2 つの例の CSV ファイル batch1.csv
と batch2.csv
を使用します。
-
batch1.csv
1, a1
2, a2
3, a3
11, a1
11, a2
12, a1 -
batch2.csv
1, a2
2, a2
3, a2
11, a2
12, a101
12, a102
13, a102