部分マージ
ClickHouseにおける部分マージとは何か?
ClickHouse は高速です ただクエリだけでなく挿入にも、高速なストレージレイヤーのおかげで、LSMツリーに類似した動作をします:
① MergeTreeエンジンファミリーのテーブルへの挿入は、ソートされた不変のデータパーツを作成します。
② すべてのデータ処理はバックグラウンド部分マージにオフロードされます。
これにより、データの書き込みが軽量かつ非常に効率的になります。
テーブルあたりのパーツの数を制御し、上記の②を実現するために、ClickHouseは常に(パーティションごと)、小さなパーツをより大きなものにバックグラウンドでマージし、圧縮サイズが約~150 GBに達するまで続けます。
以下の図は、このバックグラウンドマージプロセスを概説しています:

パーツのmerge level
は、各追加のマージごとに1ずつ増加します。0
のレベルは、パーツが新しく、まだマージされていないことを意味します。より大きなパーツにマージされたパーツは、非アクティブとしてマークされ、最終的には設定可能な時間(デフォルトで8分)後に削除されます。時間が経つにつれて、これはマージされたパーツの木を作成します。したがって、名前はマージツリーテーブルです。
マージの監視
テーブルパーツとは何かの例では、テーブルパーツを監視することを示しましたが、ClickHouseはすべてのテーブルパーツをpartsシステムテーブルで追跡します。次のクエリを使用して、例のテーブルのアクティブパーツごとのマージレベルと格納された行数を取得しました:
以前に文書化されたクエリの結果は、例のテーブルには4つのアクティブパーツがあり、各パーツは最初に挿入されたパーツの単一のマージから作成されたことを示しています:
現在実行中のクエリは、4つのパーツが最終的な単一パーツにマージされたことを示しています(テーブルにさらなる挿入がなければ):
ClickHouse 24.10では、組み込みの監視ダッシュボードに新しいマージダッシュボードが追加されました。OSSおよびCloudの両方で利用可能で、/merges
HTTPハンドラーを介して、例のテーブルのすべての部分マージを視覚化できます:

上記の記録されたダッシュボードは、初期データの挿入から最終的な単一パーツへのマージまでの全プロセスをキャッチします:
① アクティブパーツの数。
② パーツマージ、ボックスで視覚的に表現(サイズはパーツサイズを反映)。
③ 書き込み増幅。
同時マージ
単一のClickHouseサーバーは、同時にパーツマージを実行するためにいくつかのバックグラウンドマージスレッドを使用します:

各マージスレッドはループを実行します:
① 次にマージするパーツを決定し、これらのパーツをメモリにロードします。
② メモリ内のパーツをより大きなパーツにマージします。
③ マージされたパーツをディスクに書き込みます。
①に戻る
CPUコアの数とRAMのサイズを増やすことで、バックグラウンドマージのスループットを向上させることができます。
メモリ最適化マージ
ClickHouseは、前の例のように、マージされるすべてのパーツを一度にメモリにロードするわけではありません。いくつかの要因に基づき、メモリ消費を削減するため(マージ速度を犠牲にして)、いわゆる垂直マージは、ブロック単位でパーツをロードしてマージします。
マージメカニクス
以下の図は、ClickHouseの単一バックグラウンドマージスレッドがパーツをどのようにマージするかを示しています(デフォルトでは垂直マージなしで):

パーツのマージは数段階で行われます:
① デコンプレッション & ロード: マージされるパーツからの圧縮されたバイナリカラムファイルがデコンプレッションされ、メモリにロードされます。
② マージ: データはより大きなカラムファイルにマージされます。
③ インデクシング: マージされたカラムファイルのために新しいsparse primary indexが生成されます。
④ 圧縮 & ストレージ: 新しいカラムファイルとインデックスが圧縮され、マージされたデータパーツを表す新しいディレクトリに保存されます。
セカンダリデータスキッピングインデックス、カラム統計、チェックサム、最小最大インデックスなど、データパーツ内の追加メタデータも、マージされたカラムファイルに基づいて再作成されます。簡潔にするために、これらの詳細は省略しました。
ステップ②のメカニクスは、使用される特定のMergeTreeエンジンに依存し、エンジンごとにマージ方法が異なります。たとえば、行は集約されたり、古い場合は置き換えられることがあります。先に述べたように、このアプローチはすべてのデータ処理をバックグラウンドマージにオフロードし、**軽量で効率的な書き込み操作を維持することにより、超高速挿入を可能にします。
次に、MergeTreeファミリーの特定のエンジンのマージメカニクスを簡単に概説します。
標準マージ
以下の図は、標準のMergeTreeテーブルでパーツがどのようにマージされるかを示しています:

上の図のDDLステートメントは、ソートキー(town, street)
を持つMergeTree
テーブルを作成します。これは、ディスク上のデータがこれらのカラムでソートされ、対応するようにスパースプライマリインデックスが生成されることを意味します。
① デコンプレッションされ、事前にソートされたテーブルカラムが、② マージされながらテーブルのソートキーによって定義されたグローバルソート順序を保持します。③ 新しいスパースプライマリインデックスが生成され、④ マージされたカラムファイルとインデックスが圧縮されてディスク上に新しいデータパーツとして保存されます。
置換マージ
ReplacingMergeTreeテーブルの部分マージは、標準マージと同様に機能しますが、各行の最も最近のバージョンのみが保持され、古いバージョンは破棄されます:

上の図のDDLステートメントは、ソートキー(town, street, id)
を持つReplacingMergeTree
テーブルを作成します。これは、ディスク上のデータがこれらのカラムでソートされ、対応するようにスパースプライマリインデックスが生成されることを意味します。
② マージは、標準のMergeTree
テーブルと同様に作業し、デコンプレッションされ、事前にソートされたカラムを結合しながらグローバルソート順序を保持します。
ただし、ReplacingMergeTree
は、同じソートキーを持つ重複行を削除し、そのパーツの生成タイムスタンプに基づいて最も最近の行のみを保持します。
合計マージ
数値データは、SummingMergeTreeテーブルのパーツのマージ中に自動的に集約されます:

上の図のDDLステートメントは、ソートキーとしてtown
を持つSummingMergeTree
テーブルを定義し、これはディスク上でこのカラムによってデータがソートされ、対応するようにスパースプライマリインデックスが作成されることを意味します。
② のマージステップでは、ClickHouseは同じソートキーを持つすべての行を単一の行と置き換え、数値カラムの値を合計します。
集約マージ
上記のSummingMergeTree
テーブルの例は、AggregatingMergeTreeテーブルの専門的なバリアントであり、パーツのマージ中に90+の集約関数のいずれかを適用することによって、自動的な増分データ変換を可能にします:

上の図のDDLステートメントは、ソートキーとしてtown
を持つAggregatingMergeTree
テーブルを作成し、ディスク上でこのカラムによってデータが順序付けされ、対応するスパースプライマリインデックスが生成されることを保証します。
② のマージ中に、ClickHouseは同じソートキーを持つすべての行を単一の行に置き換え、部分的集約状態(例: sum
とcount
をavg()
のために)を格納します。これらの状態は、増分バックグラウンドマージを通じて正確な結果を保証します。