論理更新は現在ベータです。
問題が発生した場合は、ClickHouseリポジトリ に issue を登録してください。
UPDATE ステートメントは、式 filter_expr に一致するテーブル [db.]table の行を更新します。
これは、データパーツ内のカラム全体を書き換える重量級の処理である ALTER TABLE ... UPDATE クエリと対比して、“lightweight update” と呼ばれています。
この機能は、MergeTree テーブルエンジンファミリーでのみ利用できます。
filter_expr は UInt8 型である必要があります。このクエリは、filter_expr が非ゼロ値となる行について、指定したカラムの値を、それぞれ対応する式の値に更新します。
値は CAST 演算子を使用してカラムの型にキャストされます。プライマリキーまたはパーティションキーの計算に使用されるカラムの更新はサポートされていません。
例
論理更新ではデータは即座に更新されません
UPDATE は、パッチパート (更新されたカラムと行のみを含む特殊なデータパート) を使用して実装されています。
論理更新 UPDATE ではパッチパートが作成されますが、ストレージ内の元データが直ちに物理的に変更されるわけではありません。
更新処理は 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- パッチをデータパーツに物理的に実体化する (ミューテーション 操作)