ClickHouse 查询提速新武器:查询条件缓存

图片

本文字数:10377;估计阅读时间:26 分钟

作者: Tom Schreiber

本文在公众号【ClickHouseInc】首发

图片

在实际业务场景中,如仪表板、告警监控或交互式分析,查询往往会反复使用相同的过滤条件(WHERE 条件),无论是针对静态数据,还是不断增长的数据,比如可观测性场景中的日志查询。尽管 ClickHouse 速度很快,但这些重复扫描仍然可能带来额外的计算开销,尤其是在过滤条件具有较强的筛选能力,但又无法充分利用主索引时。

为了解决这个问题,ClickHouse 25.3 引入了 查询条件缓存(query condition cache)——一种轻量级且高效利用内存的机制,用于记录哪些数据范围符合(或不符合)特定的查询条件。该缓存以数据粒度(granule)为单位运行,使 ClickHouse 在重复执行查询时能够跳过大量无关数据,即使查询结构发生变化,也能显著提升性能。

为了庆祝我们全新 JSON 类型的 GA(正式发布),我们将通过一个真实的数据集演示查询条件缓存的工作方式:一个从热门社交媒体平台 Bluesky 采集的 JSON 事件流。同时,我们还会深入解析 ClickHouse 的数据处理流程,以及查询条件缓存在其中的作用。提前透露一下,它速度快,占用空间小,而且即便是用于查找帖子中的椒盐卷饼表情符号这样的小众需求,依然表现卓越。

让我们深入了解一下吧!

初始化数据:导入 1 亿条 JSON 事件

我们首先在一台 32 核 CPU 的测试服务器上创建一个简化的表:

CREATE TABLE bluesky
(
    data JSON(
        kind LowCardinality(String),
        time_us UInt64)
)
ORDER BY (
    data.kind,
    fromUnixTimestamp64Micro(data.time_us))
SETTINGS index_granularity_bytes = 0;

注意:设置 index_granularity_bytes = 0 会禁用自适应数据粒度阈值。这种配置 不适用于生产环境,本次实验仅使用该设置,以确保粒度大小固定,便于观察效果。

接下来,我们从 100 个存储在 S3 上的文件中导入 1 亿条 Bluesky 事件到表中:

INSERT INTO bluesky
SELECT *
FROM s3('https://clickhouse-public-datasets.s3.amazonaws.com/bluesky/file_{0001..0100}.json.gz', 'JSONAsObject')
SETTINGS
    input_format_allow_errors_num = 100,
	input_format_allow_errors_ratio = 1,
	min_insert_block_size_bytes = 0,
    min_insert_block_size_rows = 20_000_000;

注意:

  • input_format_allow_errors_* 选项可防止 ClickHouse 因少量 JSON 解析错误而终止执行。

  • min_insert_block_size_* 选项可加快数据导入速度并减少表数据合并的开销,但会占用更多内存。在低内存系统上,建议降低单次导入的行数阈值。

在正式介绍查询条件缓存之前,我们先简单了解一下 ClickHouse 的数据组织方式。

ClickHouse 的数据组织方式

目前,这张表包含 5 个数据分片,共计 1 亿行数据,未压缩数据大小为 36 GiB。

SELECT
    count() AS parts,
    formatReadableQuantity(sum(rows)) AS rows,
    formatReadableSize(sum(data_uncompressed_bytes)) AS data_size
FROM system.parts
WHERE active AND (database = 'default') AND (`table` = 'bluesky');
┌─parts─┬─rows───────────┬─data_size─┐
│     5 │ 100.00 million │ 35.87 GiB │
└───────┴────────────────┴───────────┘

在数据处理过程中,这 1 亿行数据会被划分为 粒度(granule),这是 ClickHouse 处理数据的最小单位。我们可以检查这 5 个数据分片 各自包含多少个粒度:

SELECT
    part_name,
    max(mark_number) AS granules
FROM mergeTreeIndex('default', 'bluesky')
GROUP BY part_name;
┌─part_name───┬─granules─┐
│ all_9_9_0   │     1227 │
│ all_10_10_0 │     1194 │
│ all_8_8_0   │     1223 │
│ all
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值