Lightweight Delete
轻量级的DELETE
语句会从表[db.]table
中删除与表达式expr
匹配的行。它仅适用于*MergeTree表引擎系列。
``` sql
DELETE FROM [db.]table [ON CLUSTER cluster] WHERE expr;
```
它被称为“轻量级DELETE
”以与ALTER table DELETE命令进行对比,后者是一个繁重的过程。
示例
-- 删除`hits`表中所有`Title`列包含文本`hello`的行
DELETE FROM hits WHERE Title LIKE '%hello%';
轻量级DELETE
不会立即从存储中删除数据
使用轻量级DELETE
,删除的行会立即被标记为已删除,并且会自动在所有后续查询中被过滤掉。然而,数据的清理是在下一次合并时进行的。因此,可能在未指定的时间内,数据实际上并没有从存储中删除,而只是被标记为已删除。
如果您需要保证数据在可预测的时间内从存储中删除,请考虑使用ALTER table DELETE命令。请注意,使用ALTER table DELETE
命令可能会消耗大量资源,因为它会重新创建所有受影响的部分。
删除大量数据
大量的删除可能会对ClickHouse的性能产生负面影响。如果您尝试从表中删除所有行,请考虑使用TRUNCATE TABLE
命令。
如果您预计会频繁删除数据,请考虑使用自定义分区键。然后,您可以使用ALTER TABLE...DROP PARTITION
命令快速删除与该分区相关的所有行。
轻量级DELETE
的限制
轻量级DELETE
不适用于投影
目前,DELETE
不适用于具有投影的表。这是因为投影中的行可能会受到DELETE
操作的影响,并且可能需要重建投影,从而对DELETE
的性能产生负面影响。
使用轻量级DELETE
时的性能考虑
使用轻量级DELETE
语句删除大量数据可能会对SELECT查询性能产生负面影响。
以下情况也可能对轻量级DELETE
的性能产生负面影响:
DELETE
查询中的重型WHERE
条件。- 如果变异队列中填充了许多其他变异,这可能会导致性能问题,因为表上的所有变异都是顺序执行的。
- 受影响的表具有非常多的数据部分。
- 在紧凑部分中有大量数据。在紧凑部分中,所有列都存储在一个文件中。
删除权限
DELETE
需要ALTER DELETE
权限。要为给定用户的特定表启用DELETE
语句,请运行以下命令:
GRANT ALTER DELETE ON db.table to username;
在ClickHouse中使用轻量级DELETE的内部工作原理
- 对受影响的行应用“掩码”
当执行DELETE FROM table ...
查询时,ClickHouse会保存一个掩码,其中每一行都被标记为“现有”或“已删除”。那些“已删除”的行在后续查询中会被省略。然而,实际上只有在后续合并时才会删除行。写入这个掩码比使用ALTER table DELETE
查询要轻量得多。
掩码是作为一个隐藏的_row_exists
系统列来实现的,它存储了对于所有可见行为True
,对于已删除行为False
。这个列只在部分行中存在,如果部分行中的一些行被删除了。当一个部分的所有值都等于True
时,这个列是不存在的。
- 将
SELECT
查询转换为包含掩码的查询
当查询中使用了掩码列时,SELECT ... FROM table WHERE condition
查询在内部被扩展为:
SELECT ... FROM table PREWHERE _row_exists WHERE condition
在执行时,列_row_exists
被读取以确定哪些行不应该被返回。如果有很多已删除的行,ClickHouse可以确定在读取其余列时可以完全跳过哪些粒度。
DELETE
查询被转换为ALTER table UPDATE
查询
DELETE FROM table WHERE condition
被翻译为ALTER table UPDATE _row_exists = 0 WHERE condition
变异。
在内部,这个变异是通过两个步骤来执行的:
- 对于每个单独的部分,执行
SELECT count() FROM table WHERE condition
命令来确定部分是否受到影响。 - 基于上述命令,受影响的部分然后被变异,对于未受影响的部分创建硬链接。在宽部分的情况下,为每一行更新
_row_exists
列,并且所有其他列的文件都被硬链接。对于紧凑部分,所有列都会被重新写入,因为它们都存储在一个文件中。
从上面的步骤中,我们可以看到,使用掩码技术的轻量级删除比传统的ALTER table DELETE
命令提高了性能,因为ALTER table DELETE
读取并重新写入了所有受影响部分的列文件。