論理 DELETE 文
論理削除は、MergeTree テーブルエンジンファミリにのみ利用可能で、式 expr に一致する [db.]table から行を削除します。
DELETE FROM [db.]table [ON CLUSTER cluster] [IN PARTITION partition_expr] WHERE expr;
これは、ALTER TABLE ... DELETE コマンドとの対比で「論理 削除」と呼ばれていますが、ALTER コマンドは重いプロセスです。
例
-- `Title` カラムが `hello` を含む `hits` テーブルからすべての行を削除
DELETE FROM hits WHERE Title LIKE '%hello%';
論理削除はデータを即座に削除しない
論理 DELETE は、行を削除済みとしてマークするミューテーションとして実装されており、物理的に即座に削除されません。
デフォルトでは、DELETE 文は、行が削除済みとしてマークされるまで待機してから戻ります。データ量が大きい場合、これには長時間かかることがあります。代わりに、設定 lightweight_deletes_sync を使用してバックグラウンドで非同期に実行できます。無効にすると、DELETE 文は即座に戻りますが、バックグラウンドミューテーションが終了するまでクエリに対してデータが表示され続ける可能性があります。
このミューテーションは、削除済みとマークされた行を物理的に削除しません。これは次のマージの際にのみ発生します。その結果、データがストレージから実際に削除されておらず、削除済みとマークされているだけの不特定の期間が存在する可能性があります。
予測可能な期間内にストレージからデータが削除されることを保証する必要がある場合、テーブル設定 min_age_to_force_merge_seconds の使用を検討してください。または、ALTER TABLE ... DELETE コマンドを使用することもできます。ALTER TABLE ... DELETE を使用したデータの削除は、すべての影響を受けるパーツを再作成するため、多くのリソースを消費する可能性があることに注意してください。
大量のデータを削除する
大量の削除は ClickHouse のパフォーマンスに悪影響を与える可能性があります。テーブルのすべての行を削除しようとしている場合は、TRUNCATE TABLE コマンドの使用を検討してください。
頻繁な削除が予想される場合は、カスタムパーティションキー の使用を検討してください。これによって、ALTER TABLE ... DROP PARTITION コマンドを使用して、そのパーティションに関連するすべての行をすばやく削除できます。
論理削除の制限
プロジェクションを持つ論理 DELETE
デフォルトでは、DELETE はプロジェクションを持つテーブルには対応していません。これは、プロジェクション内の行が DELETE 操作によって影響される可能性があるためです。しかし、この動作を変更する MergeTree 設定 lightweight_mutation_projection_mode があります。
論理削除を使用する際のパフォーマンス考慮事項
論理DELETE文を使用して大量のデータを削除すると、SELECT クエリのパフォーマンスに悪影響を与える可能性があります。
次の点も論理 DELETE のパフォーマンスにマイナスの影響を与える可能性があります:
DELETEクエリで重いWHERE条件がある。- ミューテーションキューが他の多くのミューテーションで満たされている場合、テーブルのすべてのミューテーションは順に実行されるため、パフォーマンスの問題につながる可能性があります。
- 影響を受けたテーブルに非常に多くのデータパーツがある。
- コンパクトパーツに大量のデータがある場合。コンパクトパーツでは、すべてのカラムが1つのファイルに保存されます。
削除の権限
DELETE には ALTER DELETE 権限が必要です。指定したユーザーに対して特定のテーブルで DELETE 文を有効にするには、次のコマンドを実行します:
GRANT ALTER DELETE ON db.table to username;
ClickHouse 内部での論理削除の動作
影響を受けた行に「マスク」が適用される
DELETE FROM table ...クエリが実行されると、ClickHouse は各行に “existing” と “deleted” のいずれかでマークされたマスクを保存します。これらの “deleted” 行は、後続のクエリでは省略されます。しかし、行は実際には後続のマージによってのみ削除されます。このマスクの書き込みは、ALTER TABLE ... DELETEクエリが行うものよりも軽量です。このマスクは、隠された
_row_existsシステムカラムとして実装され、すべての表示行に対してTrueを、削除された行に対してはFalseを格納します。このカラムは、パーツ内で一部の行が削除された場合にのみ存在します。このカラムは、すべての値がTrueである場合には存在しません。SELECTクエリはマスクを組み込むように変換されるマスクされたカラムがクエリで使用されると、
SELECT ... FROM table WHERE conditionクエリは内部的に_row_existsに対する述語で拡張され、次のように変換されます:SELECT ... FROM table PREWHERE _row_exists WHERE condition実行時に、カラム
_row_existsが読み取られ、どの行を返さないかが決定されます。大量の削除済行がある場合、ClickHouse は他のカラムを読み取る際にスキップできるグラニュールを特定できます。DELETEクエリはALTER TABLE ... UPDATEクエリに変換されるDELETE FROM table WHERE conditionは、ALTER TABLE table UPDATE _row_exists = 0 WHERE conditionミューテーションに変換されます。内部的に、このミューテーションは2段階で実行されます:
各個別パーツに対して、パーツが影響を受けているかどうかを判断するために、
SELECT count() FROM table WHERE conditionコマンドが実行されます。上記のコマンドに基づいて、影響を受けたパーツはミューテートされ、影響を受けていないパーツにはハードリンクが作成されます。ワイドパーツの場合、各行の
_row_existsカラムが更新され、他のすべてのカラムのファイルはハードリンクされます。コンパクトパーツの場合、すべてのカラムが一つのファイルに一緒に保存されているため、すべてのカラムが再書き込みされます。
上記の手順から、マスキング技術を使用した論理
DELETEは、影響を受けたパーツのすべてのカラムファイルを再書き込みしないため、従来のALTER TABLE ... DELETEに比べてパフォーマンスを改善していることがわかります。