論理更新は現在ベータです。
問題が発生した場合は、ClickHouseリポジトリ に issue を登録してください。
UPDATE ステートメントは、式 filter_expr に一致するテーブル [db.]table の行を更新します。
これは、データパーツ内のカラム全体を書き換える重量級の処理である ALTER TABLE ... 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- 元のパーツ名_block_number- 元のパーツ内におけるその行のブロック番号_block_offset- 元のパーツ内におけるその行のブロックオフセット_data_version- 更新データのデータバージョン (UPDATEクエリに割り当てられたブロック番号)
_block_number および _block_offset カラムを追加した順序でソートされます。
更新された1行あたりのストレージオーバーヘッドは、ソートキーカラムの値のサイズに依存します。
パッチパートは、元のパーツとは異なるパーティションに属します。
パッチパートのパーティションIDは patch-<hash of the patch part structure>-<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 マージアルゴリズムを使用します。
そのため、パッチパートには常に、そのパーツ内で更新された各行の最新バージョンが保持されます。
パッチパートは、テーブルのソートキーでデータパートとマージすることで適用されます。データパートとパッチパートでソートキーカラム、および _block_number と _block_offset カラムの値が等しい場合、その行は更新されます。
パッチパートの適用では、クエリで選択されていない場合でも、データパートのソートキーカラムを読み取る必要があります。
パッチパートの適用におけるメモリ使用量は、ソートキーの値が等しい行の最大範囲によって上限が定まります。
混在バージョンのクラスターにおけるパッチパートのフォーマット
patch_parts_version によって制御されます。
ClickHouse 26.8 より前のバージョンは従来の v1 フォーマットのみをサポートしており、上記で説明した現行の v2 フォーマットのパッチパートは読み取れません。
このようなバージョンからローリングアップグレードを行う場合は、すべてのレプリカのアップグレードが完了するまで v1 フォーマットで書き込みを続けてください。論理更新を使用するテーブルでは patch_parts_version = 'v1' を設定するか、アップグレード元のバージョンに compatibility 設定を指定します。
アップグレードの完了後は、オーバーライドを削除して v2 フォーマットのパッチパートの書き込みを開始します。
いずれのフォーマットのパッチパートも、設定値にかかわらず読み取りおよび適用できます。
ALTER UPDATE- 負荷の高いUPDATE操作- 論理削除
DELETE- 論理削除DELETE操作 APPLY PATCHES- パッチをデータパーツに物理的に実体化する (ミューテーション 操作)