我们是如何为 ClickHouse 列式存储构建快速 UPDATE 的 Part3/3:基准测试 1000 倍提速

图片

本文字数: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 插入

我们将重点关注两个方面:

  1. 更新速度与可见性 – 不同方法应用更改的速度差异

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 脚本):

  1. Mutation(变更)(https://github.com/ClickHouse/examples/blob/71456ae42e3bd75d23b41f5636fa7e593b941b16/blog-examples/clickhouse-fast-updates/multi-row-updates/SMALL/mutation_updates.sql)

     – 对受影响的数据 part 执行

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值