博客 / 工程

ClickHouse 23.8 版本

author avatar
ClickHouse 团队
2023年9月15日 - 14 分钟阅读

发布列车持续前进。

我们非常激动地分享 23.8 版本中的众多精彩功能

而且,我们已经确定了 23.9 版本的发布日期,请立即注册参加 9 月 28 日上午 9:00(PDT)/晚上 6:00(CEST)的社区电话会议。

版本摘要

29 个新功能。19 项性能优化。63 个错误修复。

以下是精选功能的一小部分…但此版本涵盖了向量运算、元组连接、cluster/clusterAllReplicas 的默认参数、从元数据计数(Parquet 快 5 倍)、文件中的数据跳过(再次对 Parquet 产生巨大影响)、从 s3 流式消费等等。

新贡献者

特别欢迎所有 23.6 版本的新贡献者!ClickHouse 的受欢迎程度很大程度上归功于社区的贡献。看到社区不断壮大总是令人感到荣幸。

如果您在这里看到您的名字,请与我们联系...但我们也会在推特等平台上找到您。

Al Korgun, Zamazan4ik (Alexander Zaitsev), Andy Fiddaman, Artur Malchanau, Ash Vardanian, Austin Kothig, Bhavna Jindal, Bin Xie, Dani Pozo, Daniel Pozo Escalona, Daniël van Eeden, Davit Vardanyan, Filipp Ozinov, Hendrik M, Jai Jhala, Jianfei Hu, Jiang Yuqing, Jiyoung Yoo, Joe Lynch, Kenji Noguchi, Krisztián Szűcs, Lucas Fernando Cardoso Nunes, Maximilian Roos, Nikita Keba, Pengyuan Bian, Ruslan Mardugalliamov, Selfuppen, Serge Klochkov, Sergey Katkovskiy, Tanay Tummalapalli, VanDarkholme7, Yury Bogomolov, cfanbo, copperybean, daviddhc20120601, ekrasikov, gyfis, hendrik-m, irenjj, jiyoungyoooo, jsc0218, justindeguzman, kothiga, nikitakeba, selfuppen, xbthink, xiebin, Илья Коргун, 王智博

文件、文件,以及更多文件

更快地读取文件 (Michael Kolupaev/Pavel Kruglov)

在最近的几个版本 [1][2] 中,我们重点介绍了为提高 Parquet 性能所做的努力。虽然提高性能是一段永无止境的旅程,但 23.8 版本的更改意义重大,因为它使我们对 Parquet 文件的当前读取性能更加满意。更棒的是,其中一些改进也适用于其他文件类型,例如 JSON 和 CSV。

总而言之,ClickHouse 现在

  • 通过利用 Parquet 文件中的元数据跳过读取行组,元数据捕获列的数值范围。这项期待已久的功能提供了显著的加速,我们将在下面展示。
  • 利用元数据在大多数文件格式(包括 Parquet)上提供快速计数,从而避免不必要的读取。
  • 允许在过滤器子句中使用文件名元数据来避免读取文件。当应用于 S3 等对象存储上的大型文件列表时,这可以避免大量的 I/O 并将查询时间从秒减少到毫秒。此改进适用于所有文件类型。

为了说明这些新增功能带来的好处,我们将使用 PyPI(Python 包索引)的数据集。此数据集中的每一行都代表使用 pip 等工具下载 Python 包。我们提供了包含一天内所有软件包下载量的 Parquet 文件。这包含大约 125.69GiB 的 Paquet,分布在 1657 个文件中,总共有 9 亿行。

以下所有测试均在 GCE e2-highmem-8 实例上执行,该实例具有 64GiB RAM 和 16 个内核,位于 us-central-1 的 GCS 存储桶本地。

在 23.8 版本之前,对这些文件进行计数可能会很昂贵。每个文件中的任意列都将被完整下载、读取,然后计算总数。在本地 Macbook 上运行

--23.7
SELECT count()
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')

┌───count()─┐
│ 900786589 │
└───────────┘

1 row in set. Elapsed: 26.488 sec. Processed 900.79 million rows, 134.94 GB (34.01 million rows/s., 5.09 GB/s.)

--23.8

SELECT count()
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')

1 row in set. Elapsed: 11.431 sec. Processed 900.79 million rows, 56.22 KB (78.80 million rows/s., 4.92 KB/s.)
Peak memory usage: 44.43 MiB.

太棒了,性能提高了一倍以上!此优化也适用于其他文件类型,因此好处将超出您的 Parquet 文件。

这些相同的文件有一个时间戳列,表示下载发生的时间。使用 ParquetMetadata 格式,我们可以看到此列具有描述最小值和最大值的元数据。

SELECT tupleElement(row_groups[1], 'columns')[1] AS timestamp
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/000000000000.parquet', ParquetMetadata)
FORMAT PrettyJSONEachRow
{
	"timestamp": {
    	"name": "timestamp",
    	"path": "timestamp",
    	"total_compressed_size": "681",
    	"total_uncompressed_size": "681",
    	"have_statistics": 1,
    	"statistics": {
        	"num_values": "406198",
        	"null_count": "0",
        	"distinct_count": null,
        	"min": "1690761600000000",
        	"max": "1690761650000000"
    	}
	}
}

从 23.8 版本开始,我们可以在查询时利用此元数据来加速查询。假设我们希望确定选定日期 30 分钟内的下载次数。

--23.7
SELECT
	project,
	count() AS c
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')
WHERE (timestamp >= '2023-07-31 15:30:00') AND (timestamp <= '2023-08-31 16:00:00')
GROUP BY project
ORDER BY c DESC
LIMIT 5

┌─project────────────┬───────c─┐
│ boto3          	│ 9378319 │
│ urllib3        	│ 5343716 │
│ requests       	│ 4749436 │
│ botocore       	│ 4618614 │
│ setuptools     	│ 4128870 │
└────────────────────┴─────────┘

5 rows in set. Elapsed: 83.644 sec. Processed 900.79 million rows, 134.94 GB (10.77 million rows/s., 1.61 GB/s.)

--23.8

SELECT
	project,
	count() AS c
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')
WHERE (timestamp >= '2023-07-31 15:30:00') AND (timestamp <= '2023-08-31 16:00:00')
GROUP BY project
ORDER BY c DESC
LIMIT 5

5 rows in set. Elapsed: 34.993 sec. Processed 338.86 million rows, 51.17 GB (9.68 million rows/s., 1.46 GB/s.)
Peak memory usage: 95.61 MiB.

性能再次翻倍!

这项特定的改进也 立即影响了我们的 ClickBench 结果,如下所示

clickbench_parquet.png

最后,Clickhouse 长期以来都支持文件路径中的 glob 模式。虽然这非常适合定位文件子集,但它限制了用户 glob 的表达能力。因此,ClickHouse 公开了一个 _file 虚拟列。这个隐藏的元数据列包含行来源的文件名并公开给用户。这可以在 SQL 查询中的任何位置使用,例如,计算唯一文件名的数量或限制读取的文件为子集。但是,在 23.7 及更早版本中,如果在查询的 SELECT 部分中使用此列,则需要读取整个文件。如果用户只是试图识别子集,这可能意味着读取所有文件。

此处性能提升的潜力巨大,并且将取决于子集相对于文件总数的大小。考虑以下示例,我们计算 10% 样本的唯一文件数。

--23.7

SELECT uniq(_file)
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')
WHERE (toUInt32(splitByChar('.', _file)[1]) % 10) = 0

┌─uniq(_file)─┐
│     	166 │
└─────────────┘

1 row in set. Elapsed: 4.572 sec. Processed 89.46 million rows, 13.41 GB (19.57 million rows/s., 2.93 GB/s.)

--23.8
SELECT uniq(_file)
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')
WHERE (toUInt32(splitByChar('.', _file)[1]) % 10) = 0

┌─uniq(_file)─┐
│     	166 │
└─────────────┘

1 row in set. Elapsed: 0.632 sec. Processed 89.46 million rows, 0.00 B (141.65 million rows/s., 0.00 B/s.)
Peak memory usage: 1.71 MiB.

速度提高了 7 倍!请记住,此特定优化适用于所有文件类型,而不仅仅是 Parquet。

如果需要完整位置,ClickHouse 还公开了 _path 虚拟列。

从 S3 流式消费 (Sergei Katkovskiy, Kseniia Sumarokova)

从 S3 读取数据的功能是 ClickHouse 的一项基本功能,用于执行临时数据分析以及可能是将数据迁移到 MergeTree 表中最流行的方式。从历史上看,后者的编排依赖于用户。虽然可以使用带有 s3 函数的 INSERT INTO SELECT 执行初始数据加载,但后续的增量加载通常依赖于用户构建额外的流程。这些流程可以是数据管道(使用 Kafka 等技术),或者更简单地是调度 INSERT SELECT(例如使用 cron 作业)。后者非常常见,但要确保其稳健性可能很微妙。

在 23.8 版本中,我们开始使用 S3Queue 表引擎大幅简化从 S3 进行增量加载的过程。这种新的表引擎允许从 S3 流式消费数据。当文件添加到存储桶时,ClickHouse 将自动处理这些文件并将它们插入到指定的表中。借助此功能,用户无需编写额外的代码即可设置简单的增量管道。

考虑以下简单示例。下面,我们有一个 GCS 存储桶,其中包含 PyPI 数据集的 Parquet 文件,其中每个小时由一个文件表示。

CREATE TABLE pypi_queue
ENGINE = S3Queue('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023/*.parquet')
SETTINGS mode = 'unordered'

CREATE TABLE pypi
ENGINE = MergeTree
ORDER BY (project, timestamp)
SETTINGS allow_nullable_key = 1 EMPTY AS
SELECT *
FROM pypi_queue

CREATE MATERIALIZED VIEW pypi_mv TO pypi AS
SELECT *
FROM pypi_queue

SELECT count()
FROM pypi

┌──count()─┐
│ 39082124 │
└──────────┘

1 row in set. Elapsed: 0.003 sec.

熟悉 Kafka 表引擎的用户将识别出下面提到的结构。我们在此处使用物化视图订阅 S3Queue,并将转换后的结果插入到目标 pypi 表中。

如果我们在存储桶中添加一个新文件,则表会更新

S3Queue.gif

我们在下面使用了 GCS 存储桶,这是一种与 S3 兼容的服务。此功能适用于所有与 S3 兼容的服务。

上面的 S3Queue 引擎的工作原理是定期轮询存储桶并跟踪存在的文件,将状态存储在 ClickHouse Keeper 节点中。默认情况下,每次轮询检索到的文件列表都会与存储的列表进行比较,以识别新文件。下图显示了如何处理新文件(并将其添加到 Keeper)并将其插入到队列表中。虽然这本身不存储数据,但物化视图可以订阅并在将行插入到表中以进行查询之前对其进行转换。

s3_queue_image.png

这表示简化了默认的 unordered 行为,可以对其进行调整。例如,用户可以将引擎配置为在导入文件后删除文件。这样做的好处是从 ClickHouse Keeper 中删除状态,这有助于确保跟踪的状态不会无限增长。为了防止状态无限存储,引擎还(默认情况下)仅跟踪有限数量的文件,同时还施加 TTL。在文件 TTL 过期或文件数量超过当前限制后,将重新导入文件。用户可以调整这些限制,但建议用户使用删除功能或使用 S3 功能手动使存储桶中的文件过期。

或者,可以将引擎配置为使用文件名命名和 ordered 模式。在此模式下,只有成功消费的文件的最大名称存储在 Keeper 中。在每次轮询时,仅导入名称较高的文件。这需要在文件名中强制执行排序,但避免了上述许多复杂性。

我们期待在未来几个月内改进此功能,并希望我们稍微简化了您的架构。

直接从归档导入 (Nikita Keba, Antonio Andelic, Pavel Kruglov)

作为我们最后一个功能亮点,并继续围绕文件主题,我们很高兴地宣布对归档文件的支持。ClickHouse 已经支持 zstd、lz4、snappy、gz、xz 和 bz2 等格式的压缩文件。在 23.8 版本之前,这些压缩文件只能包含单个文件。在 23.8 版本中,我们添加了对 zip、tar 和 7zip 的支持,所有这些都可以包含多个文件。

例如,我们提供了一个 1.5GB 的 zip 归档文件,其中包含 24 个 CSV 文件(解压缩后为 45GB),代表一天 9 亿行的 PyPI 数据。这些文件中的每一个都包含 PyPI 数据集中的示例列:项目、版本和时间戳,并代表一个小时的数据。下面的查询使用虚拟列 _file 计算 zip 中每个文件的行数。请注意我们如何使用 :: * 语法查询归档文件中的所有文件。

目前,仅通过 file 函数支持归档文件。因此,以下操作使用 clickhouse-local 执行。有关对 S3 等函数的支持,请继续关注!

SELECT count(), _file
FROM file('2023-08-01.zip :: *.csv')
GROUP BY _file

┌──count()─┬─_file────────────────┐
│ 47251829 │ file_download_15.csv │
│ 43946206 │ file_download_17.csv │
│ 39082124 │ file_download_0.csv  │
│ 38928391 │ file_download_21.csv │
│ 34467371 │ file_download_1.csv  │
│ 44163805 │ file_download_12.csv │
│ 43229010 │ file_download_18.csv │
│ 41974421 │ file_download_10.csv │
│ 33003822 │ file_download_4.csv  │
│ 33331289 │ file_download_23.csv │
│ 34430684 │ file_download_5.csv  │
│ 40843622 │ file_download_11.csv │
│ 41122874 │ file_download_19.csv │
│ 37279028 │ file_download_6.csv  │
│ 36118825 │ file_download_22.csv │
│ 40800076 │ file_download_7.csv  │
│ 31962590 │ file_download_2.csv  │
│ 42055283 │ file_download_20.csv │
│ 30887864 │ file_download_3.csv  │
│ 45910953 │ file_download_13.csv │
│ 43467095 │ file_download_9.csv  │
│ 46705311 │ file_download_16.csv │
│ 42704388 │ file_download_8.csv  │
│ 48248862 │ file_download_14.csv │
└──────────┴──────────────────────┘

24 rows in set. Elapsed: 97.703 sec. Processed 961.10 million rows, 48.57 GB (9.84 million rows/s., 497.11 MB/s.)
Peak memory usage: 4.04 MiB.

我们可以使用相同的 :: 表示法来定位特定文件。

SELECT toStartOfMinute(timestamp) AS minute, count() AS c
FROM file('2023-08-01.zip :: file_download_9.csv')
WHERE project = 'requests'
GROUP BY project, minute
ORDER BY minute ASC

┌──────────────minute─┬─────c─┐
│ 2023-08-01 09:00:0010944 │
│ 2023-08-01 09:01:0011076 │
│ 2023-08-01 09:02:0013705 │
│ 2023-08-01 09:03:0012460 │
│ 2023-08-01 09:04:0011379 │
│ 2023-08-01 09:05:0013363 │
│ 2023-08-01 09:06:0011438 │
…
│ 2023-08-01 09:54:007972 │
│ 2023-08-01 09:55:008641 │
│ 2023-08-01 09:56:009696 │
│ 2023-08-01 09:57:008710 │
│ 2023-08-01 09:58:007495 │
│ 2023-08-01 09:59:007692 │
└─────────────────────┴───────┘

60 rows in set. Elapsed: 7.374 sec. Processed 42.97 million rows, 2.20 GB (5.83 million rows/s., 298.59 MB/s.)
Peak memory usage: 66.99 MiB.

立即开始使用 ClickHouse Cloud,并获得 300 美元信用额度。在 30 天试用期结束时,继续使用按需付费计划,或联系我们了解有关批量折扣的更多信息。访问我们的定价页面了解详情。

分享这篇文章

订阅我们的新闻资讯

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