メインコンテンツへスキップ
論理更新は現在ベータです。 問題が発生した場合は、ClickHouseリポジトリ に issue を登録してください。
論理更新 UPDATE ステートメントは、式 filter_expr に一致するテーブル [db.]table の行を更新します。 これは、データパーツ内のカラム全体を書き換える重量級の処理である ALTER TABLE ... UPDATE クエリと対比して、“lightweight update” と呼ばれています。 この機能は、MergeTree テーブルエンジンファミリーでのみ利用できます。
UPDATE [db.]table [ON CLUSTER cluster] SET column1 = expr1 [, ...] [IN PARTITION partition_expr] WHERE filter_expr;
filter_exprUInt8 型である必要があります。このクエリは、filter_expr が非ゼロ値となる行について、指定したカラムの値を、それぞれ対応する式の値に更新します。 値は CAST 演算子を使用してカラムの型にキャストされます。プライマリキーまたはパーティションキーの計算に使用されるカラムの更新はサポートされていません。

UPDATE hits SET Title = 'Updated Title' WHERE EventDate = today();

UPDATE wikistat SET hits = hits + 1, time = now() WHERE path = 'ClickHouse';

論理更新ではデータは即座に更新されません

論理更新 UPDATE は、パッチパート (更新されたカラムと行のみを含む特殊なデータパート) を使用して実装されています。 論理更新 UPDATE ではパッチパートが作成されますが、ストレージ内の元データが直ちに物理的に変更されるわけではありません。 更新処理は INSERT ... SELECT ... クエリに似ていますが、UPDATE クエリはパッチパートの作成が完了するまで待機してから結果を返します。 更新後の値は次のとおりです。
  • パッチの適用により、SELECT クエリから即座に参照可能
  • 物理的に実体化されるのは、後続のマージやミューテーションの実行時のみ
  • アクティブなすべてのパーツでパッチが実体化されると、自動的にクリーンアップされる

論理更新の要件

論理更新は、MergeTreeReplacingMergeTreeCollapsingMergeTreeVersionedCollapsingMergeTree エンジンと、それらの Replicated および Shared バージョンでサポートされています。 論理更新を使用するには、テーブル設定 enable_block_number_columnenable_block_offset_column を使用して、_block_number および _block_offset カラムのマテリアライズを有効にする必要があります。

論理削除

論理削除 DELETE クエリは、ALTER UPDATE ミューテーションではなく、論理更新 UPDATE として実行できます。論理削除 DELETE の実装は、lightweight_delete_mode 設定によって制御されます。

パフォーマンスに関する考慮事項

論理更新の利点:
  • 更新のレイテンシは、INSERT ... SELECT ... クエリのレイテンシと同程度です
  • 書き込まれるのは更新されたカラムと値のみであり、データパーツ内のカラム全体は書き換えられません
  • 現在実行中のマージやミューテーションの完了を待つ必要がないため、更新のレイテンシは予測しやすくなります
  • 論理更新は並列に実行できます
想定されるパフォーマンスへの影響:
  • パッチを適用する必要がある SELECT クエリにはオーバーヘッドが発生します
  • パッチを適用する必要があるデータパーツ内のカラムでは、スキッピング索引 は使用されません。プロジェクション は、パッチを適用する必要がないデータパーツを含め、テーブルにパッチパートが存在する場合は使用されません。
  • 頻繁すぎる小規模な更新は、“パーツが多すぎる” エラーを引き起こす可能性があります。複数の更新を 1 つのクエリにまとめることを推奨します。たとえば、更新対象の id を 1 つの IN 句にまとめて WHERE 句で指定します
  • 論理更新は、少量の行 (テーブルの約 10% まで) を更新するように設計されています。より多くの行を更新する必要がある場合は、ALTER TABLE ... UPDATE ミューテーションを使用することを推奨します

同時実行操作

論理更新は、重い ミューテーション とは異なり、現在実行中の マージ や ミューテーション の完了を待ちません。 同時実行される論理更新の整合性は、設定 update_sequential_consistencyupdate_parallel_mode によって制御されます。

UPDATE の権限

UPDATE には ALTER UPDATE 権限が必要です。特定のテーブルで特定のユーザーに UPDATE ステートメントを許可するには、次を実行します。
GRANT ALTER UPDATE ON db.table TO username;

実装の詳細

パッチパートは通常のパーツと同じですが、更新されたカラムと、いくつかのシステムカラムのみを含みます。
  • _part - 元のパーツ名
  • _part_offset - 元のパーツ内の行番号
  • _block_number - 元のパーツ内におけるその行のブロック番号
  • _block_offset - 元のパーツ内におけるその行のブロックオフセット
  • _data_version - 更新データのデータバージョン (UPDATE クエリに割り当てられたブロック番号)
平均すると、パッチパートでは更新された1行あたり約40バイトのオーバーヘッド (非圧縮データ) が発生します。 システムカラムは、更新対象となる元のパーツ内の行を特定するのに役立ちます。 システムカラムは元のパーツ内の 仮想カラム に対応しており、パッチパートを適用する必要がある場合は、読み取り時に追加されます。 パッチパートは _part_part_offset でソートされます。 パッチパートは、元のパーツとは異なるパーティションに属します。 パッチパートのパーティションIDは patch-<hash of column names in patch part>-<original_partition_id> です。 そのため、含まれるカラムが異なるパッチパートは別々のパーティションに格納されます。 たとえば、3つの更新 SET x = 1 WHERE <cond>, SET y = 1 WHERE <cond> および SET x = 1, y = 1 WHERE <cond> によって、3つの異なるパーティションに3つのパッチパートが作成されます。 パッチパート同士をマージすることで、SELECT クエリで適用されるパッチの数を減らし、オーバーヘッドを削減できます。パッチパートのマージでは、_data_version をバージョンカラムとして replacing マージアルゴリズムを使用します。 そのため、パッチパートには常に、そのパーツ内で更新された各行の最新バージョンが保持されます。 論理更新は、現在実行中のマージやミューテーションの完了を待たず、常にデータパーツの現在のスナップショットを使用して更新を実行し、パッチパートを生成します。 そのため、パッチパートの適用には2つのケースがあります。 たとえば、パーツ A を読み取る際にパッチパート X を適用する必要があるとします。
  • X にパーツ A 自体が含まれている場合。これは、UPDATE の実行時に A がマージに参加していなかった場合に起こります。
  • X にパーツ BC が含まれており、それらがパーツ A にカバーされている場合。これは、UPDATE の実行時にマージ (B, C) -> A が進行中だった場合に起こります。
この2つのケースに対して、パッチパートの適用方法もそれぞれ2通りあります。
  • ソート済みカラム _part, _part_offset を使ったマージを使用する。
  • _block_number, _block_offset カラムを使った join を使用する。
join モードはマージモードより低速で、より多くのメモリを必要としますが、使用頻度は低めです。
最終更新日 2026年6月10日