論理更新は現在ベータです。
問題が発生した場合は、ClickHouseリポジトリ に issue を登録してください。
UPDATE ステートメントは、式 filter_expr に一致するテーブル [db.]table の行を更新します。
これは、データパーツ内のカラム全体を書き換える重量級の処理である ALTER TABLE ... UPDATE クエリと対比して、“論理更新” と呼ばれています。
この機能は、MergeTree テーブルエンジンファミリーでのみ利用できます。
filter_expr は UInt8 型である必要があります。このクエリは、filter_expr が非ゼロ値となる行について、指定したカラムの値を、それぞれ対応する式の値に更新します。
値は CAST 演算子を使用してカラムの型にキャストされます。プライマリキーまたはパーティションキーの計算に使用されるカラムの更新はサポートされていません。
IN PARTITION 句は、更新対象を指定したパーティションに限定します。これを指定しない場合、ReplicatedMergeTree ファミリーのテーブルでは、optimize_mutations_with_partition_pruning 設定が有効 (デフォルト) であれば、ClickHouse は filter_expr 内のパーティションキー条件を自動的に検出し、影響を受けるパーティションのみを更新します。非レプリケートの MergeTree テーブルでは、更新対象を特定のパーティションに限定するために、明示的な IN PARTITION 句を使用してください。
例
論理更新はクエリから即座に参照できる
論理更新UPDATE は、パッチパートを適用することで、更新後の値を SELECT クエリから即座に参照できるようにします。クエリは、更新後の値を読み取るためにマージを待つ必要がありません。
パッチパートは、更新されたカラムと行のみを含む特別な種類のデータパートです。これを作成しても、ストレージ上の元のデータがすぐに物理的に変更されるわけではありません。
更新処理は INSERT ... SELECT ... クエリに似ており、UPDATE クエリはパッチパートの作成が完了するまで待ってから制御を返します。
クエリからの可視性と物理的な実体化は別のものです:
- クエリからの可視性:
SELECTクエリは、パッチが元のデータパートに実体化される前でも、パッチを適用して更新後の値を読み取ります。 - 物理的な実体化: 後続のマージとミューテーションによって、更新後の値がデータパートに取り込まれます。
- クリーンアップ: すべてのアクティブなパーツでパッチが実体化されると、パッチパートは自動的に削除されます。
論理更新の要件
論理更新は、MergeTree、ReplacingMergeTree、CollapsingMergeTree、VersionedCollapsingMergeTree エンジンと、それらの Replicated および Shared バージョンでサポートされています。
論理更新を使用するには、テーブル設定 enable_block_number_column と enable_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_consistency と update_parallel_mode によって制御されます。
UPDATE の権限
UPDATE には ALTER UPDATE 権限が必要です。特定のテーブルで特定のユーザーに UPDATE ステートメントを許可するには、次を実行します。
実装の詳細
_part- 元のパーツ名_part_offset- 元のパーツ内の行番号_block_number- 元のパーツ内におけるその行のブロック番号_block_offset- 元のパーツ内におけるその行のブロックオフセット_data_version- 更新データのデータバージョン (UPDATEクエリに割り当てられたブロック番号)
_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にパーツBとCが含まれており、それらがパーツAにカバーされている場合。これは、UPDATEの実行時にマージ (B,C) ->Aが進行中だった場合に起こります。
- ソート済みカラム
_part,_part_offsetを使ったマージを使用する。 _block_number,_block_offsetカラムを使った join を使用する。
関連コンテンツ
ALTER UPDATE- 負荷の高いUPDATE操作- 論理削除
DELETE- 論理削除DELETE操作 APPLY PATCHES- パッチをデータパーツに物理的に実体化する (ミューテーション 操作)