ALTER 查询,最典型的就是 ALTER TABLE DELETE 这类查询。执行此类查询会生成数据分区片段的新变更版本。这意味着,对于在该变更之前插入的所有数据,这类语句都会触发整个数据分区片段的重写,从而带来大量写入请求。
对于删除操作,你可以使用 ReplacingMergeTree 或 CollapsingMergeTree 这类专用表引擎,而不是默认的 MergeTree 表引擎,以避免产生如此大量的写入请求。
[db.]table 中与表达式 expr 匹配的行。它仅适用于 *MergeTree 表引擎家族。
示例
轻量级删除不会立即删除数据
DELETE 语句会等到行被标记为已删除后才返回。如果数据量很大,这可能需要较长时间。或者,你也可以通过设置 lightweight_deletes_sync 让它在后台异步执行。禁用该设置后,DELETE 语句会立即返回,但在后台变更完成之前,这些数据对查询而言仍可能可见。
该变更不会物理删除那些已标记为删除的行;这只会在下一次合并期间发生。因此,在一段未明确的时间内,数据实际上可能并未从存储中删除,而只是被标记为已删除。
如果你需要确保数据能在可预测的时间内从存储中删除,请考虑使用表设置 min_age_to_force_merge_seconds。或者,也可以使用 ALTER TABLE … DELETE 命令。请注意,使用 ALTER TABLE ... DELETE 删除数据可能会消耗大量资源,因为它会重建所有受影响的 parts。
删除大量数据
TRUNCATE TABLE 命令。
如果你预计会频繁删除数据,建议使用自定义分区键。这样,你就可以使用 ALTER TABLE ... DROP PARTITION 命令快速删除与该分区关联的所有行。
lightweight DELETE 的局限性
带投影的轻量级删除
DELETE 不支持带投影的表。这是因为投影中的行可能会受 DELETE 操作影响。不过,可以使用 MergeTree setting lightweight_mutation_projection_mode 来更改这一行为。
使用轻量级删除时的性能注意事项
DELETE查询中的WHERE条件过于复杂。- 如果变更队列中积压了大量其他变更,也可能导致性能问题,因为表上的所有变更都是按顺序依次执行的。
- 受影响的表包含数量非常多的数据分区片段。
- compact parts 中存有大量数据。在 Compact part 中,所有列都存储在同一个文件中。
删除权限
DELETE 需要 ALTER DELETE 权限。要为特定用户启用对特定表执行 DELETE 语句的权限,请运行以下命令:
ClickHouse 中轻量级 DELETE 的内部工作机制
-
对受影响的行应用“掩码”
当执行
DELETE FROM table ...查询时,ClickHouse 会保存一个掩码,将每一行标记为“存在”或“已删除”。这些“已删除”的行会在后续查询中被忽略。不过,这些行实际上只会在之后的合并过程中才被真正移除。写入这个掩码比执行ALTER TABLE ... DELETE查询要轻量得多。 该掩码通过一个隐藏的_row_exists系统列来实现:对所有可见行存储True,对已删除的行存储False。只有当某个 part 中有行被删除时,这一列才会出现在该 part 中。如果某个 part 的所有值都等于True,则不会存在这一列。 -
SELECT查询会被改写为包含该掩码的形式 当查询中使用了带掩码的列时,SELECT ... FROM table WHERE condition查询在内部会加上_row_exists上的谓词,并被改写为:在执行时,会读取_row_exists列来确定哪些行不应返回。如果已删除的行很多,ClickHouse 还可以判断在读取其余列时,哪些粒度能够被完全跳过。 -
DELETE查询会被转换为ALTER TABLE ... UPDATE查询DELETE FROM table WHERE condition会被转换为一个ALTER TABLE table UPDATE _row_exists = 0 WHERE condition变更。 在内部,这个变更分两步执行:-
对每个单独的 part 执行一条
SELECT count() FROM table WHERE condition命令,以确定该 part 是否受影响。 -
根据上述命令的结果,对受影响的 parts 执行变更,而对未受影响的 parts 创建硬链接。对于 wide parts,会更新每一行的
_row_exists列,而其他所有列的文件都会创建硬链接。对于 compact parts,由于所有列都存储在同一个文件中,因此所有列都会被重写。
DELETE比传统的ALTER TABLE ... DELETE性能更好,因为它不需要为受影响的 parts 重写所有列文件。 -
对每个单独的 part 执行一条