Lightweight DELETE
ClickHouse 25.3 ввёл стандартный SQL-синтаксис DELETE FROM table WHERE expr — mask-based механизм удаления, который работает принципиально иначе, чем тяжёлые мутации ALTER TABLE DELETE. Понимание этой разницы критично для выбора правильного подхода к удалению данных.
Механизм: маски удаления
Когда вы выполняете DELETE FROM, ClickHouse не перезаписывает данные немедленно. Вместо этого применяется маска удаления:
- Для каждой части (part) создаётся bitmap-маска с отметкой удалённых строк
- Маска применяется немедленно ко всем
SELECT— строки исчезают из результатов - Физическая очистка происходит при следующем merge-цикле
-- Стандартный SQL DELETE (ClickHouse 25.3+, доступен в 26.3 LTS)
DELETE FROM events WHERE toDate(event_time) < '2024-01-01';
-- Строки немедленно исчезают из SELECT:
SELECT count() FROM events WHERE toDate(event_time) < '2024-01-01';
-- Результат: 0 (маска применена)
Принудительное физическое удаление (без ожидания merge):
-- Принудительная физическая очистка замаскированных строк
ALTER TABLE events APPLY DELETED MASK;
Производительность: O(parts), не O(rows)
Сложность lightweight DELETE определяется числом частей (parts), а не числом строк — это принципиальное отличие от тяжёлых мутаций:
| Операция | Сложность | Синхронность | Механизм |
|---|---|---|---|
DELETE FROM (lightweight) | O(parts) | Синхронная (маска) | Bitmap-маска на part |
ALTER TABLE DELETE (mutation) | O(rows × cols) | Асинхронная | Полная перезапись колонок |
DROP PARTITION | O(1) | Синхронная | Переименование директории |
Для таблицы с 10 миллиардами строк в 1000 частях:
DELETE FROM— обходит 1000 частей для создания масок (~секунды)ALTER TABLE DELETE— перезаписывает все колонки во всех строках (~часы)
Ограничение: несовместимость с projections
Lightweight DELETE несовместим с таблицами, содержащими projections. Попытка выполнить DELETE FROM на такой таблице завершится ошибкой.
Причина: mask-based механизм не обновляет projection parts — они остаются с устаревшими данными. ClickHouse отклоняет операцию для защиты консистентности.
Решение для таблиц с projections: используйте тяжёлую мутацию ALTER TABLE t DELETE WHERE ....
-- Таблица с projection:
CREATE TABLE events_with_proj (
user_id UInt64,
event_time DateTime,
event_type String
) ENGINE = MergeTree
ORDER BY (user_id, event_time);
ALTER TABLE events_with_proj ADD PROJECTION user_summary (
SELECT user_id, count() GROUP BY user_id
);
-- ЭТО ЗАВЕРШИТСЯ ОШИБКОЙ:
-- DELETE FROM events_with_proj WHERE user_id = 42;
-- Error: Lightweight delete is not supported for tables with projections
-- Правильный подход для таблиц с projections:
ALTER TABLE events_with_proj DELETE WHERE user_id = 42;
Когда использовать Lightweight DELETE
Lightweight DELETE оптимален в следующих сценариях:
- GDPR/право на забвение: удаление данных конкретного пользователя (< 10% строк таблицы)
- Точечная коррекция: удаление некорректных записей после загрузки
- Таблицы без проекций: если нет
ALTER TABLE ... ADD PROJECTION - Требование немедленной видимости: маска применяется синхронно, данные исчезают сразу
Не используйте Lightweight DELETE если:
- Таблица содержит projections →
ALTER TABLE DELETE - Нужно удалить > 10% строк → рассмотрите
DROP PARTITION - Требуется точечное освобождение диска без ожидания merge →
APPLY DELETED MASKилиALTER TABLE DELETE
-- Проверка наличия projections в таблице:
SELECT name, type FROM system.projections WHERE table = 'events';
-- Мониторинг замаскированных строк (до физической очистки):
SELECT
table,
sum(rows) AS total_rows,
sum(data_compressed_bytes) AS compressed_size
FROM system.parts
WHERE table = 'events' AND active
GROUP BY table;
Ключевые выводы
DELETE FROM(25.3+) создаёт bitmap-маску: строки исчезают из SELECT немедленно, физическая очистка при merge.- Сложность O(parts) — принципиально быстрее мутаций O(rows × cols) для точечных удалений.
ALTER TABLE t APPLY DELETED MASKпринудительно очищает диск без ожидания merge.- Lightweight DELETE несовместим с таблицами, содержащими projections — для них используйте
ALTER TABLE t DELETE WHERE .... - Иерархия производительности:
DROP PARTITION>>DELETE FROM(lightweight) >>ALTER TABLE DELETE(mutation).