博客 / 工程

ClickHouse 24.11 版本发布

author avatar
ClickHouse 团队
2024 年 12 月 6 日 - 8 分钟阅读

又一个月过去了,这意味着又到了发布新版本的时候了!

ClickHouse 24.11 版本包含 9 个新功能 🦃、15 项性能优化 ⛸️ 和 68 个错误修复 🏕️

在此版本中,并行哈希连接成为默认连接策略,WITH FILL 获得了 STALENESS 修饰符,您可以预热标记缓存,并且向量搜索通过 BFloat16 数据类型变得更快。

新贡献者

与往常一样,我们特别欢迎 24.11 版本中的所有新贡献者!ClickHouse 的受欢迎程度很大程度上归功于社区的贡献。看到社区不断壮大总是令人感到荣幸。

以下是新贡献者的姓名

0xMihalich, Max Vostrikov, Payam Qorbanpour, Plasmaion, Roman Antonov, Romeo58rus, Zoe Steinkamp, kellytoole, ortyomka, qhsong, udiz, yun, Örjan Fors, Андрей

提示:如果您好奇我们如何生成此列表……这里

您还可以查看演示文稿的幻灯片

并行哈希连接是默认连接策略

由 Nikita Taranov 贡献

并行哈希连接算法现在是默认连接策略,取代了哈希连接。

并行哈希连接算法是哈希连接的一种变体,它拆分输入数据以并发构建多个哈希表,从而以更高的内存开销为代价来加速连接。您可以在下面的算法查询管道图中看到一个图表

Parallel Hash Join.png

您可以在ClickHouse 连接内幕 - 哈希连接、并行哈希连接、优雅哈希连接博客文章中了解有关并行哈希连接的更多信息。

除了成为默认设置外,还对该算法进行了性能优化,其中在线程之间分散以进行并行处理的块现在使用零拷贝而不是每次都复制块列。

ORDER BY WITH FILL 的 STALENESS 修饰符

由 Mikhail Artemenko 贡献

此版本为 WITH FILL 引入了 STALENESS 子句。让我们借助 MidJourney 数据集 来看看如何使用它。假设我们已经下载了 Parquet 文件,我们可以使用以下查询来填充表

1CREATE TABLE images (
2    id String,
3    timestamp DateTime64,
4    height Int64,
5    width Int64,
6    size Int64
7
8)
9ENGINE = MergeTree
10ORDER BY (size, height, width);
11
12
13INSERT INTO images WITH data AS (
14  SELECT
15    assumeNotNull(timestamp) AS ts,
16    assumeNotNull(id) AS id,
17    assumeNotNull(height) AS height,
18    assumeNotNull(width) AS width,
19    assumeNotNull(size) AS size,
20    parseDateTime64BestEffort(ts) AS ts2
21  FROM file('data/0000{00..55}.parquet')
22)
23SELECT id, ts2 AS timestamp,  height, width, size
24FROM data;

假设我们想要计算 2023 年 3 月 24 日一秒钟内生成的图像数量。我们将使用参数定义开始和结束日期

  
1SET param_start = '2023-03-24 00:24:02', 
2    param_end = '2023-03-24 00:24:03';

然后我们可以编写此查询来计算每 100 毫秒的计数,使用 WITH FILL 子句用零值填充空桶

1SELECT
2    toStartOfInterval(timestamp, toIntervalMillisecond(100)) AS bucket,
3    count() AS count, 'original' as original
4FROM MidJourney.images
5WHERE (timestamp >= {start: String}) AND (timestamp <= {end: String})
6GROUP BY ALL
7ORDER BY bucket ASC
8WITH FILL
9FROM toDateTime64({start:String}, 3)
10TO toDateTime64({end:String}, 3) STEP toIntervalMillisecond(100);
┌──────────────────bucket─┬─count─┬─original─┐
│ 2023-03-24 00:24:02.0000 │          │
│ 2023-03-24 00:24:02.1000 │          │
│ 2023-03-24 00:24:02.2000 │          │
│ 2023-03-24 00:24:02.3003 │ original │
│ 2023-03-24 00:24:02.4000 │          │
│ 2023-03-24 00:24:02.5000 │          │
│ 2023-03-24 00:24:02.6001 │ original │
│ 2023-03-24 00:24:02.7001 │ original │
│ 2023-03-24 00:24:02.8002 │ original │
│ 2023-03-24 00:24:02.9000 │          │
└─────────────────────────┴───────┴──────────┘

此版本引入了 STALENESS 子句。来自文档

当定义 STALENESS const_numeric_expr 时,查询将生成行,直到与原始数据中前一行的差异超过 const_numeric_expr

您不能同时使用 STALENESSWITH FILL...FROM 子句,因此我们需要删除它,这将使我们得到以下查询

1SELECT
2    toStartOfInterval(timestamp, toIntervalMillisecond(100)) AS bucket,
3    count() AS count, 'original' as original
4FROM MidJourney.images
5WHERE (timestamp >= {start: String}) AND (timestamp <= {end: String})
6GROUP BY ALL
7ORDER BY bucket ASC
8WITH FILL
9TO toDateTime64({end:String}, 3) STEP toIntervalMillisecond(100);

删除 WITH FILL...FROM 子句意味着我们的结果集将从第一个实际值开始,而不是用 0 预填充到指定的时间戳。

┌──────────────────bucket─┬─count─┬─original─┐
│ 2023-03-24 00:24:02.3003 │ original │
│ 2023-03-24 00:24:02.4000 │          │
│ 2023-03-24 00:24:02.5000 │          │
│ 2023-03-24 00:24:02.6001 │ original │
│ 2023-03-24 00:24:02.7001 │ original │
│ 2023-03-24 00:24:02.8002 │ original │
│ 2023-03-24 00:24:02.9000 │          │
└─────────────────────────┴───────┴──────────┘

如果我们现在添加 200 毫秒的 STALENESS 值,它将仅填充空行,直到与前一行的差异超过 200 毫秒

1SELECT
2    toStartOfInterval(timestamp, toIntervalMillisecond(100)) AS bucket,
3    count() AS count, 'original' as original
4FROM MidJourney.images
5WHERE (timestamp >= {start: String}) AND (timestamp <= {end: String})
6GROUP BY ALL
7ORDER BY bucket ASC
8WITH FILL
9TO toDateTime64({end:String}, 3) STEP toIntervalMillisecond(100)
10STALENESS toIntervalMillisecond(200);
┌──────────────────bucket─┬─count─┬─original─┐
│ 2023-03-24 00:24:02.3003 │ original │
│ 2023-03-24 00:24:02.4000 │          │
│ 2023-03-24 00:24:02.6001 │ original │
│ 2023-03-24 00:24:02.7001 │ original │
│ 2023-03-24 00:24:02.8002 │ original │
│ 2023-03-24 00:24:02.9000 │          │
└─────────────────────────┴───────┴──────────┘

我们从结果集中丢失了以下行

2023-03-24 00:24:02.5000 │          │

HTTP 接口中的异常

由 Sema Checherinda 贡献

即使在结果已流式传输到客户端之后,HTTP 接口现在也可以可靠地检测错误。在以前的版本中,如果我们针对 ClickHouse 服务器运行以下查询

1curl https://127.0.0.1:8123/?output_format_parallel_formatting=0 -d "SELECT throwIf(number > 100000) FROM system.numbers FORMAT Values"

我们会看到一系列值,然后在末尾附加此错误消息

Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(number, 100000) :: 2) -> throwIf(greater(number, 100000)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 24.3.1.465 (official build))

退出代码为 0,这表明查询已成功运行。从 24.11 版本开始,我们将看到以下输出

Code: 395. DB::Exception: Value passed to 'throwIf' function is non-zero: while executing 'FUNCTION throwIf(greater(__table1.number, 100000_UInt32) :: 0) -> throwIf(greater(__table1.number, 100000_UInt32)) UInt8 : 1'. (FUNCTION_THROW_IF_VALUE_IS_NON_ZERO) (version 24.11.1.2557 (official build))
curl: (18) transfer closed with outstanding read data remaining

并且我们的非零代码为 18。

预热标记缓存

由 Anton Popov 贡献

标记映射将主键映射到每个列文件中的偏移量,构成表索引的一部分。每个表列都有一个标记文件。它们会占用大量内存,并且有选择地加载到标记缓存中。

从 24.11 版本开始,您可以使用 mark_cache_prewarm_ratio 设置来预热此缓存,默认设置为 95%。

服务器在每次插入、合并或提取数据部分时,都会急切地将标记带入内存中的缓存,直到几乎满为止。

一个新的系统命令 SYSTEM PREWARM MARK CACHE t 将立即将所有标记加载到缓存中。

BFloat16 数据类型

由 Alexey Milovidov 贡献

Bfloat16 数据类型由 Google Brain 开发,用于表示向量嵌入。顾名思义,它由 16 位组成——一个符号位、一个 8 位指数,然后是 7 位尾数/小数。

2024-12-05_13-19-27.png

它具有与 Float32(单精度浮点数)相同的指数范围,但尾数的位数较少(7 位而不是 23 位)。

此数据类型现在在 ClickHouse 中可用,并将有助于 AI 和向量搜索。您需要配置以下设置才能使用新类型

SET allow_experimental_bfloat16_type=1;

我们在单台机器 AWS c7a.metal-48xl 上对 2800 万个 384 维向量进行了全扫描的最近邻搜索,并看到了以下结果

clickhouse-benchmark --query "WITH
[-0.02925783360957671,-0.03488947771094666,...,0.032484047621093616]::Array(BFloat16)
AS center SELECT d FROM (SELECT cosineDistance(vector, center) AS d
    FROM hackernews_llama_memory ORDER BY d LIMIT 10
) SETTINGS allow_experimental_bfloat16_type = 1"
BFloat16: 0.061 sec, 301 GB/sec.
Float32: 0.146 sec, 276 GB/sec.
分享此帖子

订阅我们的新闻通讯

随时了解功能发布、产品路线图、支持和云产品!
正在加载表单...
关注我们
X imageSlack imageGitHub image
Telegram imageMeetup imageRss image
©2025ClickHouse, Inc. 总部位于加利福尼亚州湾区和荷兰阿姆斯特丹。