軽量更新ステートメント
軽量更新は現在ベータ版です。 問題が発生した場合は、ClickHouseリポジトリで問題を報告してください。
軽量の UPDATE
ステートメントは、式 filter_expr
に一致するテーブル [db.]table
の行を更新します。
これは、データパーツの全列を書き換える重いプロセスである ALTER TABLE ... UPDATE
クエリと対比するために「軽量更新」と呼ばれています。
これは、MergeTree
テーブルエンジンファミリーでのみ利用可能です。
filter_expr
は UInt8
型でなければなりません。このクエリは、filter_expr
がゼロでない値を取る行の指定されたカラムの値を、対応する式の値に更新します。
値は CAST
演算子を使用してカラム型にキャストされます。主キーまたはパーティションキーの計算に使用されるカラムの更新はサポートされていません。
例
軽量更新はデータを即座には更新しない
軽量 UPDATE
は パッチパーツ - 更新されたカラムと行のみを含む特別なデータパートを使用して実装されています。
軽量 UPDATE
はパッチパーツを作成しますが、ストレージ内の元のデータを物理的に即座には変更しません。
更新プロセスは INSERT ... SELECT ...
クエリに似ていますが、UPDATE
クエリはパッチパートの作成が完了するまで待機します。
更新された値は次の通りです:
- 即座に可視化 される
SELECT
クエリを通じてパッチの適用によって - 物理的にマテリアライズ されるのは、その後のマージやミューテーションの際のみです
- 自動的にクリーンアップ されるのは、すべてのアクティブパーツがパッチをマテリアライズした後です
軽量更新の要件
軽量更新は、MergeTree
、ReplacingMergeTree
、CollapsingMergeTree
エンジンおよびそれらの 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
クエリにオーバーヘッドが追加されます - スキッピングインデックス は、パッチが適用されるデータパーツのカラムには使用されません。プロジェクション は、パッチが適用されるデータパーツを含むテーブルにパッチパーツが存在する場合には使用されません。
- あまりにも頻繁すぎる小さな更新は、「パーツが多すぎる」というエラーにつながる可能性があります。例えば、複数の更新を単一のクエリにバッチ処理することをお勧めします。つまり、更新するためのIDを
WHERE
句の単一のIN
句に入れることです。 - 軽量更新は、少量の行(テーブルの約10%まで)を更新するために設計されています。より多くを更新する必要がある場合は、
ALTER TABLE ... UPDATE
ミューテーションの使用をお勧めします。
同時操作
軽量更新は、重いミューテーションとは異なり、現在実行中のマージやミューテーションの完了を待ちません。
同時軽量更新の整合性は、設定 update_sequential_consistency
と update_parallel_mode
によって制御されます。
更新権限
UPDATE
には ALTER UPDATE
権限が必要です。特定のテーブルに対する特定のユーザーの UPDATE
ステートメントを有効にするには、次のコマンドを実行します:
実装の詳細
パッチパーツは通常のパーツと同じですが、更新されたカラムといくつかのシステムカラムのみを含みます:
_part
- 元のパーツ名_part_offset
- 元のパーツ内の行番号_block_number
- 元のパーツ内の行のブロック番号_block_offset
- 元のパーツ内の行のブロックオフセット_data_version
- 更新されたデータのデータバージョン(UPDATE
クエリのために割り当てられたブロック番号)
平均して、パッチパーツの各更新行には約40バイト(非圧縮データ)のオーバーヘッドがかかります。
システムカラムは、更新すべき元のパーツ内の行を見つけるのに役立ちます。
システムカラムは、パッチパーツが適用されるべき場合に読み取りのために追加される元のパーツの仮想カラムに関連しています。
パッチパーツは、_part
と _part_offset
によってソートされます。
パッチパーツは元のパーツとは異なるパーティションに属します。
パッチパーツのパーティションIDは patch-<patchパーツのカラム名のハッシュ>-<original_partition_id>
です。
したがって、異なるカラムを持つパッチパーツは、異なるパーティションに格納されます。
例えば、三つの更新 SET x = 1 WHERE <cond>
、SET y = 1 WHERE <cond>
、SET x = 1, y = 1 WHERE <cond>
は、三つの異なるパーティションに三つのパッチパーツを作成します。
パッチパーツは、お互いにマージ可能で、SELECT
クエリにおける適用されたパッチの数を減らし、オーバーヘッドを減少させます。パッチパーツのマージは、_data_version
をバージョンカラムとして使用した置換マージアルゴリズムを使用します。
そのため、パッチパーツは常に部分内の各更新行の最新バージョンを保存します。
軽量更新は、現在実行中のマージやミューテーションが完了するのを待たず、常にデータパーツの現在のスナップショットを使用して更新を実行し、パッチパーツを生成します。 そのため、パッチパーツを適用する場合に二つのケースが考えられます。
例えば、部分 A
を読み取り、そのパッチ部分 X
を適用する必要がある場合:
X
がA
自身を含む場合。UPDATE
が実行されたときにA
がマージに参加していなかった場合に発生します。X
がB
とC
を含み、これらが部分A
にカバーされている場合。UPDATE
が実行されたときにマージ(B
、C
)->A
が実行中だった場合に発生します。
これら二つのケースに対して、それぞれパッチパーツを適用する二つの方法があります:
- ソートされたカラム
_part
、_part_offset
によるマージを使用します。 _block_number
、_block_offset
カラムによるジョインを使用します。
ジョインモードはマージモードよりも遅く、より多くのメモリを必要としますが、あまり頻繁には使用されません。
関連コンテンツ
ALTER UPDATE
- 重いUPDATE
操作- 軽量
DELETE
- 軽量DELETE
操作