ビットマップを使用した正確な Count Distinct
このトピックでは、CelerData でビットマップを使用して異なる値の数を計算する方法について説明します。
ビットマップは、配列内の異なる値の数を計算するための便利なツールです。この方法は、従来の Count Distinct と比較して、ストレージスペースを節約し、計算を高速化できます。配列 A が [0, n) の範囲の値を持つと仮定します。(n+7)/8 バイトのビットマップを使用することで、配列内の異なる要素の数を計算できます。これを行うには、すべてのビットを 0 に初期化し、要素の値をビットの添字として設定し、すべてのビットを 1 に設定します。ビットマップ内の 1 の数が、配列内の異なる要素の数です。
従来の Count Distinct
CelerData は MPP アーキテクチャを使用しており、Count Distinct を使用する際に詳細データを保持できます。しかし、Count Distinct 機能はクエリ処理中に複数のデータシャッフルを必要とし、これによりリソースが多く消費され、データ量が増加するにつれてパフォーマンスが線形に低下します。
次のシナリオでは、テーブル (dt, page, user_id) の詳細データに基づいて UV を計算します。
dt | page | user_id |
---|---|---|
20191206 | game | 101 |
20191206 | shopping | 102 |
20191206 | game | 101 |
20191206 | shopping | 101 |
20191206 | game | 101 |
20191206 | shopping | 101 |
CelerData は次の図に従ってデータを計算します。最初に page
と user_id
列でデータをグループ化し、その後処理された結果をカウントします。
- 注: 図は、2 つの BE ノードで計算された 6 行のデータの概略を示しています。
大量のデータを扱う際に複数のシャッフル操作が必要な場合、計算リソースが大幅に増加する可能性があります。これによりクエリが遅くなります。しかし、ビットマップ技術を使用することで、この問題に対処し、クエリパフォーマンスを向上させることができます。
page
でグループ化して uv
をカウントします:
select page, count(distinct user_id) as uv from table group by page;
| page | uv |
| :---: | :---: |
| game | 1 |
| shopping | 2 |