メインコンテンツへスキップ
削除ミューテーションとは、削除によってテーブルデータを操作する ALTER クエリのことです。代表的なものとして、ALTER TABLE DELETE などがあります。こうしたクエリを実行すると、データパーツの新しいミューテーション済みバージョンが生成されます。つまり、このようなステートメントは、ミューテーションより前に挿入されたすべてのデータについてデータパーツ全体の書き換えをトリガーするため、大量の書き込みリクエストが発生します。
削除では、デフォルトの MergeTree テーブルエンジンの代わりに、ReplacingMergeTreeCollapsingMergeTree などの専用テーブルエンジンを使用することで、こうした大量の書き込みリクエストを回避できます。
論理 DELETE ステートメントは、式 expr に一致するテーブル [db.]table の行を削除します。これは *MergeTree テーブルエンジンファミリーでのみ使用できます。
DELETE FROM [db.]table [ON CLUSTER cluster] [IN PARTITION partition_expr] WHERE expr;
これは、負荷の大きい ALTER TABLE … DELETE コマンドと区別するために、「論理削除」と呼ばれます。

-- `hits` テーブルから `Title` カラムに `hello` というテキストを含むすべての行を削除する
DELETE FROM hits WHERE Title LIKE '%hello%';

論理削除 ではデータはすぐには削除されません

論理削除 は、行を削除済みとしてマークするものの、ただちに物理的に削除はしない ミューテーション として実装されています。 デフォルトでは、DELETE ステートメントは、行を削除済みとしてマークする処理が完了するまで待機してから戻ります。データ量が多い場合、この処理には時間がかかることがあります。あるいは、設定 lightweight_deletes_sync を使用して、バックグラウンドで非同期に実行することもできます。これを無効にすると、DELETE ステートメントはすぐに戻りますが、バックグラウンドの ミューテーション が完了するまでは、データがクエリから見え続ける可能性があります。 この ミューテーション では、削除済みとしてマークされた行は物理的には削除されません。実際に削除されるのは、次回の merge 時のみです。そのため、一定期間のあいだ、データは実際にはストレージから削除されず、削除済みとしてマークされているだけの状態になる可能性があります。 データが予測可能な時間内にストレージから確実に削除されるようにしたい場合は、テーブル設定 min_age_to_force_merge_seconds の使用を検討してください。あるいは、ALTER TABLE … DELETE コマンドを使用することもできます。ALTER TABLE ... DELETE によるデータ削除では、影響を受けるすべてのパーツを再作成するため、大量のリソースを消費する可能性がある点に注意してください。

大量のデータの削除

大量の削除は ClickHouse のパフォーマンスに悪影響を与える可能性があります。テーブル内のすべての行を削除したい場合は、TRUNCATE TABLE コマンドの使用を検討してください。 削除が頻繁に発生することが見込まれる場合は、カスタムのパーティションキーの使用を検討してください。これにより、ALTER TABLE ... DROP PARTITION コマンドを使って、そのパーティションに関連するすべての行をすばやく削除できます。

論理削除 の制約

プロジェクションがある場合の論理削除

デフォルトでは、DELETE はプロジェクションを持つテーブルでは使用できません。これは、プロジェクション内の行が DELETE 操作の影響を受ける可能性があるためです。ただし、この挙動は MergeTree 設定 lightweight_mutation_projection_mode で変更できます。

論理削除 使用時のパフォーマンスに関する考慮事項

論理削除 ステートメントで大量のデータを削除すると、SELECT クエリのパフォーマンスに悪影響を及ぼす可能性があります。 また、次の要因も論理削除 のパフォーマンスに悪影響を与える可能性があります。
  • DELETE クエリ内の負荷の高い WHERE 条件。
  • ミューテーションキューが多数の他のミューテーションで埋まっている場合、テーブル上のすべてのミューテーションは順次実行されるため、パフォーマンスの問題につながる可能性があります。
  • 対象のテーブルに非常に多くのデータパーツがある。
  • compact パーツに大量のデータがあること。compact パーツでは、すべてのカラムが 1 つのファイルに格納されます。

DELETE 権限

DELETE を実行するには、ALTER DELETE 権限が必要です。特定のユーザーが特定のテーブルで DELETE ステートメントを実行できるようにするには、次のコマンドを実行します。
GRANT ALTER DELETE ON db.table to username;

ClickHouse における論理削除の内部的な仕組み

  1. 影響を受ける行に「マスク」が適用される DELETE FROM table ... クエリが実行されると、ClickHouse は各行が「existing」か「deleted」かを示すマスクを保存します。以降のクエリでは、「deleted」とマークされた行は除外されます。ただし、行が実際に削除されるのは、その後のマージ時です。このマスクの書き込みは、ALTER TABLE ... DELETE クエリで行われる処理に比べてはるかに軽量です。 このマスクは、可視状態のすべての行に True、削除された行に False を格納する隠しシステムカラム _row_exists として実装されています。このカラムは、パーツ内で一部の行が削除されている場合にのみ存在します。パーツ内のすべての値が True の場合、このカラムは存在しません。
  2. SELECT クエリはマスクを含む形に変換される マスク対象のカラムがクエリで使用される場合、SELECT ... FROM table WHERE condition クエリには内部的に _row_exists に対する述語が追加され、次のように変換されます。
    SELECT ... FROM table PREWHERE _row_exists WHERE condition
    
    実行時には、返すべきでない行を判定するために _row_exists カラムが読み取られます。削除された行が多い場合、ClickHouse は残りのカラムを読む際に、どの granule を完全にスキップできるかを判断できます。
  3. DELETE クエリは ALTER TABLE ... UPDATE クエリに変換される DELETE FROM table WHERE condition は、ALTER TABLE table UPDATE _row_exists = 0 WHERE condition ミューテーションに変換されます。 内部的には、このミューテーションは次の 2 段階で実行されます。
    1. 各パーツが影響を受けるかどうかを判定するため、各パーツごとに SELECT count() FROM table WHERE condition コマンドが実行されます。
    2. 上記のコマンドの結果に基づいて、影響を受けるパーツにはミューテーションが適用され、影響を受けないパーツにはハードリンクが作成されます。wide パーツ の場合は各行の _row_exists カラムが更新され、その他のすべてのカラムのファイルにはハードリンクが作成されます。compact パーツ の場合はすべてのカラムが 1 つのファイルにまとめて格納されているため、すべてのカラムが再書き込みされます。
    以上の手順から、マスキング手法を用いた論理削除の DELETE は、影響を受けるパーツに対してすべてのカラムファイルを書き直す必要がないため、従来の ALTER TABLE ... DELETE よりも高い性能を発揮することがわかります。
最終更新日 2026年6月10日