軽量更新ステートメント
軽量更新は現在ベータ版です。 問題が発生した場合は、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操作