メインコンテンツへスキップ
更新の処理方法は、基盤となる設計思想や想定ユースケースが異なるため、分析データベースとトランザクションデータベースとで大きく異なります。 ClickHouse は、読み取り中心の分析処理と高スループットな追記専用操作向けに最適化された カラム指向データベース です。 実際には、削除や更新を追記操作に変換し、それを非同期または読み取り時に処理できるように、テーブルを再構成することがよくあります。これにより、高スループットなデータインジェストにおける ClickHouse の強みを活かせます。 ClickHouse は、強力な更新および削除操作にも対応しています。 このガイドでは、ClickHouse で利用できる更新方法の概要を示し、ワークロードに適した更新戦略を選ぶ際の参考情報を提供します。

更新戦略の選択

ClickHouse でデータを更新するには、基本的に 2 つのアプローチがあります。
  1. insert によって更新を処理する 専用のテーブルエンジン を使用する
  2. UPDATE ... SETALTER TABLE ... UPDATE のような 宣言的な更新 ステートメントを使用する
上記 2 つのカテゴリには、それぞれデータを更新する方法がいくつかあります。 それぞれに利点と性能特性があるため、データモデルと更新したいデータ量に応じて、適切な方法を選択してください。

専用のテーブルエンジンを使う場合

専用のテーブルエンジンは、大量の更新がある場合、行レベルの変更が頻繁に発生する場合、または更新イベントや削除イベントの継続的なストリームを処理する必要がある場合に、より適しています。 一般的によく使われるエンジンは次のとおりです。 MergeTree ファミリーのテーブルエンジンはバックグラウンドでデータパーツをマージするため、結果整合性 を提供します。そのため、完全にマージされるまでの間にテーブルをクエリする際は、適切に重複排除するために FINAL キーワードを使用する必要があります。 ほかにもエンジンの種類はありますが、これらが最も一般的に使われます。

宣言的更新を使用するタイミング

宣言的な UPDATE ステートメントは、重複排除ロジックを管理する複雑さがなく、単純な更新処理ではより扱いやすい場合があります。ただし一般に、専用エンジンを使う方法と比べると、比較的少ない行を低頻度で更新する用途に向いています。

専用のテーブルエンジンを使った更新

ReplacingMergeTree

ReplacingMergeTree は、バックグラウンドマージ時に同じソートキーを持つ行を重複排除し、最新バージョンのみを保持します。
このエンジンは、安定したキーで更新を識別する、個々の行に対する高頻度の更新に最適です。 ベンチマークでは、単一行の更新において ミューテーション より最大 4,700 倍高速であることが示されています。 行を更新するには、同じソートキーの値と、より大きいバージョン番号を持つ新しいバージョンを insert するだけです。古いバージョンは background merges の過程で削除されます。重複排除は最終的に行われるもの (つまり merges のときにのみ発生します) であるため、正しく重複排除された結果を得るには、FINAL 修飾子または同等のクエリロジックを使用する必要があります。FINAL 修飾子を使うと、データに応じてクエリのオーバーヘッドが 21~550% 増加します。 ReplacingMergeTree ではソートキーの値は更新できません。また、論理削除用の Deleted カラムもサポートしています。 詳細: ReplacingMergeTree ガイド | ReplacingMergeTree リファレンス

CoalescingMergeTree

CoalescingMergeTree は、マージ時に各カラムの最新の非 NULL 値を保持することで、スパースなレコードを統合します。これにより、行全体を置き換えるのではなく、カラム単位で upsert できます。
このエンジンは、複数のデータソースから断片的にデータが到着する場合や、異なるカラムがそれぞれ別のタイミングで埋められる場合を想定して設計されています。一般的なユースケースとしては、断片化されたサブシステムからの IoT テレメトリー、ユーザープロファイルのエンリッチメント、次元データの到着が遅れる ETL パイプラインなどがあります。 同じソートキーを持つ行がマージされると、CoalescingMergeTree は行全体を置き換えるのではなく、各カラムについて NULL でない最新の値を保持します。これを意図どおりに機能させるには、キー以外のカラムを Nullable にする必要があります。ReplacingMergeTree と同様に、正しく統合された結果を得るには FINAL を使用してください。 このエンジンは ClickHouse 25.6 から利用できます。 詳細: CoalescingMergeTree

CollapsingMergeTree

更新はコストが高い一方で、挿入を利用して更新を実現できるという考え方に基づき、CollapsingMergeTreeSign カラムを使って、マージ時に ClickHouse が行をどのように処理するかを指定します。Sign カラムに -1 が挿入されると、その行は対応する +1 の行と対になったときに折りたたまれ (削除され) ます。更新対象の行は、テーブル作成時に ORDER BY 句で使用するソートキーに基づいて識別されます。
ReplacingMergeTreeとは異なり、CollapsingMergeTreeではソートキーの値を変更できます。金融取引やゲーム状態の追跡など、取り消しを前提とした可逆的な操作に適しています。
上記の更新方法では、打ち消し用の行を挿入するために、アプリケーション側でクライアントの状態を保持しておく必要があります。これは ClickHouse の観点では最も効率的ですが、大規模環境では扱いが複雑になることがあります。また、正しい結果を得るには、クエリでも符号の乗算を伴う集約が必要です。
詳細: CollapsingMergeTree

宣言的更新

これらの方法は、MergeTree family エンジンを使用するテーブルで利用できます。

ミューテーション

ミューテーション (ALTER TABLE ... UPDATE) は、WHERE 式に一致する行を含むすべてのパーツを再書き込みします。
ミューテーションは I/O 負荷が高く、WHERE 式に一致するすべてのパーツを書き換えます。 このプロセスにはアトミック性がありません。 パーツは準備でき次第、変更後のパーツに置き換えられるため、ミューテーションの実行中に開始された SELECT クエリでは、すでにミューテーションされたパーツのデータと、まだミューテーションされていないパーツのデータの両方が見えることになります。 進行状況は system.mutations テーブルで確認できます。
ミューテーションは I/O 集約的で、クラスターの SELECT パフォーマンスに影響する可能性があるため、使用は最小限にとどめてください。ミューテーションが処理されるより速くキューにたまると、クエリのパフォーマンスは低下します。キューは system.mutations で監視してください。
詳細: ALTER TABLE UPDATE

オンザフライミューテーション

ALTER TABLE ... UPDATE によるミューテーションでは、変更後の値がクエリ結果に反映されるまで、バックグラウンドプロセスによってミューテーションが適用されるのを待つ必要がある場合があります。 ClickHouse では、“オンザフライミューテーション” によってこの動作を変更できます。 オンザフライミューテーションを有効にすると、更新された行は即座に更新済みとしてマークされ、後続の SELECT クエリでは変更後の値が自動的に返されます。 オンザフライミューテーションは、クエリレベルの設定 apply_mutations_on_fly を有効にすることで、MergeTree ファミリーのテーブルで使用できます。
テーブルを作成し、いくつかのミューテーションを実行してみましょう。
SELECT クエリで更新結果を確認してみましょう。
新しいテーブルに対してクエリを実行した時点では、行の値はまだ更新されていないことに注意してください。
次に、オンザフライミューテーションを有効にするとどうなるかを見てみましょう。
これで SELECT クエリは、ミューテーションが適用されるのを待つことなく、直ちに正しい結果を返します。
パフォーマンスへの影響
オンザフライミューテーションが有効になっている場合、ミューテーションはすぐにはマテリアライズされず、SELECT クエリの実行時にのみ適用されます。ただし、ミューテーションのマテリアライズ自体は引き続きバックグラウンドで非同期に行われており、これは負荷の高い処理である点に注意してください。 一定の期間にわたって、投入されるミューテーション数がバックグラウンドで処理されるミューテーション数を継続的に上回ると、適用が必要な未マテリアライズのミューテーションのキューは増え続けます。その結果、最終的に SELECT クエリのパフォーマンスが低下します。 未マテリアライズのミューテーションが際限なく増え続けるのを防ぐため、設定 apply_mutations_on_fly は、number_of_mutations_to_thrownumber_of_mutations_to_delay などの他の MergeTree レベルの設定とあわせて有効にすることを推奨します。
サブクエリおよび非決定論的関数のサポート
オンザフライミューテーションでのサブクエリおよび非決定論的関数のサポートには制限があります。サポートされるのは、結果サイズが適切な範囲内にあるスカラーサブクエリのみです (設定 mutations_max_literal_size_to_replace で制御されます) 。また、非決定論的関数については、定数となるもののみがサポートされます (例: 関数 now()) 。 これらの動作は、次の設定で制御されます。

論理更新

論理更新では、従来のミューテーションのようにカラム全体を書き換えるのではなく、更新されたカラムと行だけを含む特殊なデータパートである”パッチパート”を使用します。
このアプローチでは標準の UPDATE 構文を使用し、マージを待たずにパッチパートを即座に作成します。更新された値は、パッチの適用によって SELECT クエリですぐに参照できますが、物理的に反映されるのは後続のマージ時のみです。そのため、論理更新は、予測可能なレイテンシで少数の行 (テーブルの約 10% まで) を更新するのに最適です。ベンチマークでは、ミューテーションと比べて最大 23 倍高速になることが示されています。 その一方で、SELECT クエリではパッチの適用に伴うオーバーヘッドが発生し、パッチパートはパーツ数の上限にもカウントされます。約 10% のしきい値を超えると、読み取り時のパッチ適用オーバーヘッドが比例して増加するため、より大規模な更新では同期ミューテーションのほうが効率的です。 詳細: Lightweight UPDATE

オンザフライミューテーション

オンザフライミューテーションは、行を更新した際に、その後のSELECTクエリでバックグラウンド処理の完了を待たずに変更後の値が自動的に返される仕組みです。これにより、通常のミューテーションにおけるアトミック性の制約を実質的に解消できます。
ミューテーションと、それに続く SELECT クエリの両方で、apply_mutations_on_fly = 1 設定を有効にする必要があります。ミューテーションの条件は ClickHouse Keeper に保存され、Keeper はそれらをすべてメモリ内に保持し、クエリ実行時にオンザフライで適用します。 データの更新には引き続きミューテーションが使用される点に注意してください。違うのは、すぐには実体化されないということだけです。ミューテーションは非同期プロセスとしてバックグラウンドで引き続き適用され、通常のミューテーションと同じ大きなオーバーヘッドが発生します。また、この操作で使用できる式にも制限があります (詳細を参照) 。
オンザフライミューテーションは、ごく少数の操作にのみ使用してください。多くても数十件程度までに抑えるべきです。Keeper は条件をメモリ内に保存するため、過剰に使用するとクラスターの安定性に影響します。Keeper に高い負荷がかかると、無関係なテーブルにも影響するセッションタイムアウトが発生する可能性があります。
詳しくは: On-the-fly mutations

比較のまとめ

次の表は、ベンチマークに基づいて、クエリ性能に生じるオーバーヘッドをまとめたものです。ミューテーションは、完了してデータが物理的に書き換えられた後はクエリがフルスピードで実行されるため、基準として扱っています。

関連資料

ClickHouse における更新機能がどのように進化してきたのかや、ベンチマーク分析を詳しく知りたい場合は、以下を参照してください。
最終更新日 2026年6月25日