- 継続的に変化するオブジェクトの状態を高速に書き込めます。
- 古いオブジェクトの状態をバックグラウンドで削除します。これにより、ストレージ使用量を大幅に削減できます。
VersionedCollapsingMergeTree は CollapsingMergeTree と同じ目的で使用されますが、異なる折りたたみアルゴリズムを採用しているため、複数のスレッドでデータを任意の順序で挿入できます。特に、Version カラムによって、行が誤った順序で挿入された場合でも正しく折りたたむことができます。一方、CollapsingMergeTree では厳密に連続した挿入しかできません。
テーブルの作成
エンジンパラメータ
クエリ句
VersionedCollapsingMergeTree テーブルを作成する場合、MergeTree テーブルの作成時と同じ 句 が必要です。
折りたたみ
データ
Sign カラムを使用します。Sign = 1 は、その行がオブジェクトの状態を表すことを意味します (これを 状態行と呼ぶことにします) 。Sign = -1 は、同じ属性を持つオブジェクトの状態を取り消すことを示します (これを 取消行と呼ぶことにします) 。また、Version カラムも使用します。これは、オブジェクトの各状態をそれぞれ異なる番号で識別するためのものです。
たとえば、あるサイトでユーザーが何ページ閲覧し、どれくらいの時間滞在したかを計算したいとします。ある時点で、ユーザーのアクティビティの状態として次の行を書き込みます。
Sign を除き、打ち消す対象の状態のすべてのフィールドをコピーする必要があります。
2番目の行には現在の状態が含まれます。
ユーザーアクティビティの最後の状態だけが必要なので、これらの行は
VersionedCollapsingMergeTree は、データパーツのマージ時にこれを行います。
変更ごとに 2 行が必要な理由については、Algorithm を参照してください。
使用上の注意
- データを書き込むプログラムは、その状態を取り消せるよう、オブジェクトの状態を記憶しておく必要があります。“Cancel” 文字列には、主キーフィールドのコピー、“state” 文字列のバージョン、および反対の
Signを含める必要があります。これによりストレージの初期サイズは増えますが、データをすばやく書き込めます。 - カラム内で長く増え続ける配列は、書き込み時の負荷によりエンジンの効率を低下させます。データは単純であるほど効率が高くなります。
SELECTの結果は、オブジェクト変更履歴の整合性に大きく依存します。insert 用のデータを準備するときは、正確さに十分注意してください。データに整合性がないと、セッション深度のような非負のメトリクスで負の値が出るなど、予測不能な結果になることがあります。
アルゴリズム
Sign が異なる行の各ペアを削除します。行の順序は問いません。
ClickHouse がデータを挿入するとき、行は主キー順に並べられます。Version カラムが主キーに含まれていない場合、ClickHouse はそれを暗黙的に主キーの最後のフィールドとして追加し、並べ替えに使用します。
データの選択
SELECT クエリを複数のスレッドで処理するため、結果内の行の順序を予測できません。つまり、VersionedCollapsingMergeTree テーブルから完全に「折りたたまれた」データを取得する必要がある場合は、集約が必要です。
折りたたみを確定するには、GROUP BY 句と、符号を考慮した集約関数を使ったクエリを記述します。たとえば、件数を計算するには count() の代わりに sum(Sign) を使用します。何らかの値の合計を計算するには、sum(x) の代わりに sum(Sign * x) を使用し、さらに HAVING sum(Sign) > 0 を追加します。
集約 count、sum、avg はこの方法で計算できます。集約 uniq は、あるオブジェクトに少なくとも 1 つの折りたたまれていない状態がある場合に計算できます。集約 min と max は、VersionedCollapsingMergeTree が折りたたまれた状態の値の履歴を保存しないため、計算できません。
「折りたたみ」後のデータを集約せずに取り出す必要がある場合 (たとえば、最新の値が特定の条件に一致する行が存在するかどうかを確認する場合) は、FROM 句で FINAL 修飾子を使用できます。この方法は非効率なため、大きなテーブルでは使用すべきではありません。
使用例
INSERT クエリを2つ使用します。データを1つのクエリで挿入すると、ClickHouse は1つのデータパーツを作成し、その後マージは実行されません。
データの取得:
INSERT クエリによって、2 つのデータパーツが作成されました。SELECT クエリは 2 つのスレッドで実行されたため、結果の行の順序はランダムになります。
折りたたみが発生していないのは、データパーツがまだマージされていないためです。ClickHouse は、予測できない不定のタイミングでデータパーツをマージします。
このため、集約が必要です:
FROM 句で FINAL 修飾子を使用できます。