Skip to content
ClickHouse Docs
ClickHouse DocsClickHouse Docs

パーツのマージ

ClickHouse におけるパーツマージとは何ですか?


ClickHouse が高速なのは、クエリだけでなく insert でも同様です。これは、LSM trees に似た仕組みで動作するストレージ層によるものです。

MergeTree エンジン ファミリーのテーブルへの insert では、ソート済みで不変のデータパーツが作成されます。

② すべてのデータ処理は、バックグラウンドでのパーツマージにオフロードされます。

その結果、データの書き込みは軽量で、非常に効率的になります。

テーブルごとのパーツ数を制御し、上記の ② を実現するために、ClickHouse はバックグラウンドで小さなパーツを大きなパーツへ継続的にマージし (パーティションごと) 、圧縮サイズがおよそ ~150 GB に達するまでこれを続けます。

次の図は、このバックグラウンドマージのプロセスを概略的に示したものです。

パーツマージ

パーツの merge level は、マージのたびに 1 ずつ増加します。レベル 0 は、そのパーツが新規作成されたもので、まだマージされていないことを意味します。より大きなパーツにマージされたパーツはinactiveとしてマークされ、最終的には設定可能な時間の経過後に削除されます (デフォルトは 8 分) 。時間の経過とともに、これによりマージ済みパーツのツリーが形成されます。これが merge tree テーブルという名前の由来です。

マージの監視

テーブルパーツとはの例では、ClickHouse がすべてのテーブルパーツを parts システムテーブルで追跡していることを示しました。この例のテーブルにあるアクティブな各パーツについて、マージレベルと保存されている行数を取得するために、次のクエリを使用しました。

SELECT
    name,
    level,
    rows
FROM system.parts
WHERE (database = 'uk') AND (`table` = 'uk_price_paid_simple') AND active
ORDER BY name ASC;

前述のドキュメントのクエリ結果から、この例のテーブルにはアクティブなパーツが4つあり、各パーツは最初に挿入されたパーツを1回マージして作成されたことがわかります。

   ┌─name────────┬─level─┬────rows─┐
1. │ all_0_5_1   │     1 │ 6368414 │
2. │ all_12_17_1 │     1 │ 6442494 │
3. │ all_18_23_1 │     1 │ 5977762 │
4. │ all_6_11_1  │     1 │ 6459763 │
   └─────────────┴───────┴─────────┘

クエリを実行すると、4 つのパーツがその後 1 つの最終的なパーツにマージされたことがわかります (テーブルへのそれ以上の insert がない場合) :

   ┌─name───────┬─level─┬─────rows─┐
1. │ all_0_23_2 │     2 │ 25248433 │
   └────────────┴───────┴──────────┘

ClickHouse 24.10 では、新しいマージダッシュボードが組み込みの監視ダッシュボードに追加されました。これは OSS と Cloud の両方で /merges HTTP ハンドラー経由で利用でき、この例のテーブルで発生するすべてのパーツマージを可視化できます。

パーツマージ

上のダッシュボードの録画では、最初のデータ挿入から単一パーツへの最終的なマージまで、プロセス全体を確認できます。

① アクティブなパーツ数。

② ボックスで視覚的に表したパーツマージ (サイズはパーツの大きさを反映) 。

書き込み増幅

並行マージ

1 台の ClickHouse サーバーは、複数のバックグラウンドマージスレッドを使用して、パーツの同時マージを実行します。

パーツマージ

各マージスレッドは、次のループを実行します。

パーツをメモリに読み込む

次にマージするパーツを決定し、それらのパーツをメモリに読み込みます。

パーツをマージする

メモリ内でパーツをより大きなパーツにマージします。

ディスクに書き込む

マージされたパーツをディスクに書き込み、ステップ 1 に戻ります。

CPU コア数と RAM 容量を増やすことで、バックグラウンドマージのスループットを向上させることができます。

メモリ最適化されたマージ

ClickHouse では、前の例で示したように、マージ対象のすべてのパーツを必ずしも一度にメモリへ読み込むわけではありません。いくつかの要因に応じて、メモリ消費を抑えるために (そのぶんマージ速度は低下します) 、いわゆる垂直マージでは、パーツを一括で処理するのではなく、ブロックの chunk ごとに読み込んでマージします。

マージの仕組み

以下の図は、ClickHouse における単一のバックグラウンドマージスレッドが、パーツをどのようにマージするかを示しています (デフォルトでは、垂直マージは使用しません) :

パーツマージ

パーツマージは、いくつかのステップで実行されます:

解凍と読み込み

マージ対象のパーツに含まれる圧縮済みバイナリカラムファイルを解凍し、メモリに読み込みます。

マージ

データを、より大きなカラムファイルへマージします。

索引作成

マージ後のカラムファイルに対して、新しいスパースプライマリインデックスが生成されます。

圧縮と保存

新しいカラムファイルと索引は圧縮され、マージ後のデータパーツを表す新しいディレクトリに保存されます。

また、セカンダリのデータスキッピングインデックス、カラム STATISTICS、チェックサム、min-max 索引 などのデータパーツ内の追加メタデータも、マージ後のカラムファイルに基づいて再作成されます。ここでは簡略化のため、これらの詳細は省略しています。

マージステップの仕組みは、使用するMergeTree エンジンによって異なります。これは、エンジンごとにマージの処理方法が異なるためです。たとえば、古くなった行が集計されたり、置き換えられたりすることがあります。前述のとおり、このアプローチではすべてのデータ処理をバックグラウンドマージにオフロードするため、書き込み処理を軽量かつ効率的に保ち、超高速な insertを実現できます。

次に、MergeTree family に属する各エンジンのマージの仕組みを簡単に見ていきます。

標準マージ

以下の図は、標準的なMergeTreeテーブルでパーツがどのようにマージされるかを示しています。

パーツマージ

上図のDDLステートメントは、ソートキーが (town, street)MergeTree テーブルを作成します。つまり、ディスク上のデータはこれらのカラムでソートされ、それに応じてスパースプライマリインデックスが生成されることを意味します

① 圧縮解除され、あらかじめソートされたテーブルのカラムが、テーブルのソートキーで定義された全体のソート順を維持したまま ② マージされ、③ 新しいスパースプライマリインデックスが生成され、④ マージ後のカラムファイルと索引が圧縮されて、ディスク上の新しいデータパーツとして保存されます。

Replacing マージ

ReplacingMergeTree テーブルのパーツマージは、標準的なマージ と同様に動作しますが、各行については最新バージョンのみが保持され、古いバージョンは破棄されます。

パーツマージ

上の図の DDL ステートメントは、ソートキー (town, street, id) を持つ ReplacingMergeTree テーブルを作成しています。これは、ディスク上のデータがこれらのカラム順にソートされ、それに応じてスパースプライマリインデックスが生成されることを意味します。

② のマージ処理は、標準的な MergeTree テーブルと同様に動作し、グローバルなソート順を維持しながら、解凍済みで事前にソートされたカラムを結合します。

ただし、ReplacingMergeTree では同じソートキーを持つ重複行が削除され、その行を含むパーツの作成タイムスタンプに基づいて最新の行だけが保持されます。


加算マージ

数値データは、SummingMergeTree テーブルのパーツのマージ時に自動的に集計されます。

パーツマージ

上の図の DDLステートメントでは、town をソートキーとする SummingMergeTree テーブルを定義しています。これは、ディスク上のデータがこのカラムでソートされ、それに対応するスパースプライマリインデックスが作成されることを意味します。

② のマージ処理では、ClickHouse は同じソートキーを持つすべての行を 1 つの行に置き換え、数値カラムの値を合計します。

集計マージ

前述の SummingMergeTree テーブルの例は、AggregatingMergeTree テーブルの特化版であり、パートのマージ時に 90+ の任意の集計関数を適用することで、データの自動インクリメンタル変換 を可能にします。

パーツマージ

上の図の DDL ステートメントは、town をソートキーとする AggregatingMergeTree テーブルを作成し、このカラムに基づいてデータがディスク上で順序付けられ、対応するスパースプライマリインデックスが生成されるようにします。

② のマージ中、ClickHouse は同じソートキーを持つすべての行を、部分集計状態 を格納した 1 行に置き換えます (たとえば、avg() に対する sumcount) 。これらの状態により、インクリメンタルなバックグラウンドマージを通じて正確な結果が保証されます。

Navigation