选择更新策略
- 使用专用表引擎,通过插入操作完成更新
- 使用声明式更新,例如
UPDATE ... SET或ALTER TABLE ... UPDATE语句
何时使用专用表引擎
由于 MergeTree 家族的表引擎会在后台合并数据分区片段,因此它们提供的是_最终一致性_;在此期间查询表时,需要使用
FINAL 关键字来确保正确去重。
此外还有其他引擎类型,但这些是最常用的几种。
何时使用声明式更新
使用专用表引擎更新数据
ReplacingMergeTree
ReplacingMergeTree 会在后台合并过程中对具有相同排序键的行进行去重,仅保留最新版本。
FINAL modifier 或等效的查询逻辑,以获得正确的去重结果。FINAL modifier 会增加查询开销,具体增加 21% 到 550%,取决于数据情况。
ReplacingMergeTree 无法更新 排序键 值。它还支持使用 Deleted 列进行逻辑删除。
延伸阅读:ReplacingMergeTree 指南 | ReplacingMergeTree 参考
CoalescingMergeTree
Nullable。与 ReplacingMergeTree 一样,使用 FINAL 以获得正确的合并结果。
该引擎自 ClickHouse 25.6 起可用。
阅读更多:CoalescingMergeTree
CollapsingMergeTree
CollapsingMergeTree 使用 Sign 列来告诉 ClickHouse 在 merge 过程中如何处理各行。如果向 sign 列插入 -1,那么当该行与对应的 +1 行配对时,就会被折叠 (删除) 。需要更新的行,是根据创建表时 ORDER BY 子句中使用的 排序键 来识别的。
ReplacingMergeTree 不同,CollapsingMergeTree 允许你修改排序键的值。它非常适合带有抵消语义的可逆操作,例如金融交易或游戏状态追踪。
上述更新方法要求你的应用在客户端侧维护状态,以便插入抵消行。虽然从 ClickHouse 的角度看,这是效率最高的方式,但在大规模场景下使用起来可能会比较复杂。查询还需要结合 sign 乘法进行聚合,才能得到正确的结果。
声明式更新
变更
ALTER TABLE ... UPDATE) 会重写所有包含符合 WHERE 表达式的行的 parts。
WHERE expression 的 parts。
这一过程不具备原子性。
parts 会在变更后的 parts 准备就绪后立即被替换,而在变更过程中开始执行的 SELECT 查询,会同时看到已完成变更的 parts 中的数据和仍未变更的 parts 中的数据。
你可以通过 system.mutations 表跟踪进度状态。
阅读更多:ALTER TABLE UPDATE
即时变更
ALTER TABLE ... UPDATE 执行变更时,你可能需要等待后台进程完成这些变更,才能在查询结果中看到更新后的值。
ClickHouse 提供了“即时变更”机制,可改变这一行为。
启用即时变更后,更新过的行会立即被标记为已更新,后续的 SELECT 查询会自动返回更新后的值。
对于 MergeTree 家族的表,可以通过启用查询级设置 apply_mutations_on_fly 来开启即时变更。
示例
示例
让我们创建一个表,并执行一些变更:让我们通过 请注意,在查询这个新建的表时,这些行的值还没有更新:现在我们来看看启用即时变更后会发生什么:现在,
SELECT 查询来查看更新结果:SELECT 查询会立即返回正确结果,无需等待变更实际应用完成:性能影响
SELECT 查询时应用。不过请注意,变更仍会在后台异步物化,而这一过程开销很大。
如果在一段时间内,已提交的变更数量持续超过后台处理的变更数量,待应用的未物化变更队列就会不断增长。这最终会导致 SELECT 查询性能下降。
我们建议将设置 apply_mutations_on_fly 与其他 MergeTree 级别的设置 (例如 number_of_mutations_to_throw 和 number_of_mutations_to_delay) 配合启用,以限制未物化变更队列的无限增长。
对子查询和非确定性函数的支持
mutations_max_literal_size_to_replace 控制) 。仅支持常量非确定性函数 (例如 now() 函数) 。
这些行为由以下设置控制:
轻量级更新
UPDATE 语法,会立即创建补丁分区片段,而无需等待合并。更新后的值会通过补丁应用立即反映在 SELECT 查询结果中,但只有在后续合并时才会被实际物化到存储中。这使得轻量级更新非常适合更新少量行 (约占整张表的 10% 以内) ,并且能够提供可预测的延迟。基准测试表明,其速度最高可比变更快 23 倍。
代价是,SELECT 查询在应用补丁时会产生额外开销,而且补丁分区片段也会占用 parts 数量限制。超过约 10% 这一阈值后,读取时应用补丁的开销会按比例增长,因此对于更大规模的更新,同步变更会更高效。
更多信息:轻量级 UPDATE
即时变更
即时变更提供了一种更新行的机制,使后续的SELECT 查询无需等待后台处理完成,即可自动返回变更后的值。这实际上解决了常规变更在原子性方面的局限。
SELECT 查询都需要启用 apply_mutations_on_fly = 1 设置。变更条件存储在 ClickHouse Keeper 中;它将所有内容保存在内存中,并在查询期间即时应用。
请注意,更新数据仍然是通过变更完成的——只是不会立即物化。变更仍会作为异步过程在后台应用,并产生与常规变更相同的高额开销。此操作可使用的表达式也有一定限制 (请参见详情) 。
阅读更多:即时变更