
本文字数:19684;估计阅读时间:50 分钟
作者:Tom Schreiber
本文在公众号【ClickHouseInc】首发

TL;DR
标准 SQL UPDATE 功能登陆 ClickHouse:借助轻量级补丁分区更新机制,性能可比传统变更(mutation)快 1,000 倍。
本文是 ClickHouse 快速 UPDATE 系列的第三篇:
介绍 ClickHouse 如何通过基于插入的引擎(如 ReplacingMergeTree、CollapsingMergeTree 和 CoalescingMergeTree)避免低效的行级更新。
讲述我们如何利用补丁分区机制,以极低的额外开销将标准 UPDATE 语法引入 ClickHouse。
-
本篇:基准测试与结果
全面对比多种更新方式的性能,其中包括声明式 UPDATE,实际测得最高可达 1,000 倍的加速效果。
ClickHouse 中的快速 SQL 更新:基准测试与咖啡因加持下的松鼠
想象一只松鼠,身形灵巧,在不同储藏点之间来回穿梭,不停地放入新坚果。
再想象这只松鼠喝了浓缩咖啡——速度快到惊人,眨眼间就能在储藏点间完成往返。
这就是 ClickHouse 轻量级更新 的体验:在数据分区间飞快穿梭,投递微小补丁,即刻生效,同时保持查询性能稳定。
剧透:这些是真正的标准 SQL UPDATE,通过轻量级补丁分区机制实现。在我们的基准测试中,一次批量标准 SQL UPDATE 从 100 秒缩短到 60 毫秒,比经典变更快 1,600 倍,而在最差情况下,查询性能几乎与完全重写数据时相当。
本文是 ClickHouse 快速 UPDATE 深度解析的第 3 部分,重点介绍基准测试结果。
(如果想了解背后的实现细节,请参考 第 2 部分:SQL 语法的 UPDATE。)
在这里,我们将并列对比多种 UPDATE 方法:
-
经典变更与即时执行的变更
-
轻量级更新(补丁分区)
-
ReplacingMergeTree 插入
我们将重点关注两个方面:
- 更新速度与可见性 – 不同方法应用更改的速度差异
2. 合并前的查询性能影响 – 在数据合并前更新对延迟的影响
所有测试均可完整复现,我们已开源全部脚本和查询。
接下来,我们将介绍数据集和基准测试配置,然后逐步分析测试结果。
数据集与基准测试配置
数据集
在 第 1 部分和 第 2 部分 中,我们曾用一个小型订单表来演示基础更新场景。
在本次基准测试中,我们继续沿用“订单”主题,但将规模大幅提升,选用 TPC-H(https://clickhouse.com/docs/getting-started/example-datasets/tpch) 数据集中的 lineitem 表,该表模拟了客户订单中的商品条目。这是一个典型的更新场景,数量、价格或折扣在最初插入后可能会发生变化。
CREATE TABLE lineitem (
l_orderkey Int32,
l_partkey Int32,
l_suppkey Int32,
l_linenumber Int32,
l_quantity Decimal(15,2),
l_extendedprice Decimal(15,2),
l_discount Decimal(15,2),
l_tax Decimal(15,2),
l_returnflag String,
l_linestatus String,
l_shipdate Date,
l_commitdate Date,
l_receiptdate Date,
l_shipinstruct String,
l_shipmode String,
l_comment String)
ORDER BY (l_orderkey, l_linenumber);
我们使用的是该表的 规模因子 100(scale factor 100) 版本,包含约 6 亿行数据(约 1.5 亿个订单中的 6 亿个商品),压缩后大小约 30 GiB(未压缩约 60 GiB)。
在基准测试中,lineitem 表以单个 数据 part(https://clickhouse.com/docs/parts) 形式存储。其压缩大小约 30 GiB,远低于 ClickHouse 150 GiB 压缩合并 阈值(https://clickhouse.com/docs/operations/settings/merge-tree-settings#max_bytes_to_merge_at_max_space_in_pool)——该阈值以内,后台合并会自动将多个较小的 part 合并为一个。这意味着该表会自然保持为一个完全合并的单 part,能够很好地模拟实际的更新场景。
下面是我们用于所有基准测试运行的 lineitem 基表(https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/init.sh#L68) 概览,确认其为单个数据 part。
SELECT
formatReadableQuantity(sum(rows)) AS row_count,
formatReadableQuantity(count()) AS part_count,
formatReadableSize(sum(data_uncompressed_bytes)) AS size_uncomp,
formatReadableSize(sum(data_compressed_bytes)) AS size_comp
FROM system.parts
WHERE active AND database = 'default' AND `table` = 'lineitem_base_tbl_1part';
┌─row_count──────┬─part_count─┬─size_uncomp─┬─size_comp─┐
│ 600.04 million │ 1.00 │ 57.85 GiB │ 26.69 GiB │
└────────────────┴────────────┴─────────────┴───────────┘
硬件与操作系统
测试运行环境为一台 AWS m6i.8xlarge EC2 实例(32 核 CPU、128 GB 内存),搭配 gp3 EBS 卷(16k IOPS,最大吞吐量 1000 MiB/s),运行 Ubuntu 24.04 LTS。
ClickHouse 版本
所有测试均基于 ClickHouse 25.7 进行。
如何自行运行
你可以使用我们在 GitHub 提供的基准测试脚本(https://github.com/ClickHouse/examples/tree/main/blog-examples/clickhouse-fast-updates)复现所有结果。
该代码仓库包含:
-
批量更新和单行更新的 SQL 语句集
-
用于运行基准测试并记录耗时的脚本
-
检查数据 part 大小和分析查询性能影响的辅助工具
在测试环境与数据集准备就绪后,我们从批量更新开始探索不同更新方法的表现,因为批量更新是大多数批处理流水线的核心场景。
批量 UPDATE
批量更新是批处理数据管道的基础,也是经典 mutation 最常见的工作负载。因此我们首先对其进行评测。
我们针对 10 个典型的批量更新场景 进行了基准测试,采用三种方法(GitHub 上均提供了对应的 SQL 脚本):
- Mutation(变更)(https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/mutation_updates.sql)
– 对受影响的数据 part 执行

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



