ClickHouse 25.4 版本发布说明

图片

本文字数:8739;估计阅读时间:22 分钟

作者: ClickHouse Team

本文在公众号【ClickHouseInc】首发

图片

新的一月,迎来全新版本!

发布概要

ClickHouse 25.4 带来了 25 项新功能 🌸 23 项性能优化 🦋 以及 58 个缺陷修复 🐝

此次更新引入了延迟物化(lazy materialization)、Apache Iceberg 的时光回溯功能、用于 EXISTS 子句的相关子查询(correlated subquery)等一系列重要特性。

新贡献者

热烈欢迎所有在 25.4 版本中首次提交的贡献者!ClickHouse 社区的持续壮大令人欣喜,我们始终感激所有推动项目不断发展的贡献者们。

以下是本次版本中的新贡献者名单:

Amol Saini, Drew Davis, Elmi Ahmadov, Fellipe Fernandes, Grigory Korolev, Jia Xu, John Doe, Luke Gannon, Muzammil Abdul Rehman, Nikolai Ryzhov, ParvezAhamad Kazi, Pavel Shutsin, Saif Ullah, Samay Sharma, Shahbaz Aamir, Sumit, Todd Yocum, Vladimir Baikov, Wudidapaopao, Xiaozhe Yu, arf42, cjw, felipeagfranceschini, krzaq, wujianchao5, zouyunhe

延迟物化(Lazy materialization)

贡献者:Xiaozhe Yu

延迟物化是 ClickHouse 推出的一项查询优化新特性,它可以将列数据的读取推迟到真正需要时再执行。在包含排序和 LIMIT 的 Top N 查询中,这项优化能让 ClickHouse 跳过大部分数据的加载,从而大幅降低 I/O 开销、内存消耗,并显著缩短运行时间。

来看一个真实场景中的例子:下面的查询会找出拥有最多“有帮助”投票数的 Amazon 用户评论,并返回排名前 3 条的标题、副标题和完整内容。

首先,我们在关闭延迟物化(并清空文件系统缓存)的情况下运行该查询:

SELECT helpful_votes, product_title, review_headline, review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
FORMAT Null
SETTINGS query_plan_optimize_lazy_materialization = false;
0 rows in set. Elapsed: 219.071 sec. Processed 150.96 million rows, 71.38 GB (689.08 thousand rows/s., 325.81 MB/s.)
Peak memory usage: 1.11 GiB.

然后,在再次清空文件系统缓存后,我们启用延迟物化,运行同一个查询:

SELECT helpful_votes, product_title, review_headline, review_body
FROM amazon.amazon_reviews
ORDER BY helpful_votes DESC
LIMIT 3
FORMAT Null
SETTINGS query_plan_optimize_lazy_materialization = true;
0 rows in set. Elapsed: 0.139 sec. Processed 150.96 million rows, 1.81 GB (1.09 billion rows/s., 13.06 GB/s.)
Peak memory usage: 3.80 MiB.

结果令人惊艳:性能提升了 1,576 倍!I/O 开销减少了 40 倍,内存占用降低了 300 倍。

查询相同、数据表相同、运行环境也相同。

唯一的变化?只是 ClickHouse 读取数据的时机不同。

Tom Schreiber 最近撰写了一篇名为《ClickHouse 变得更懒(也更快):引入延迟物化》的博客【https://clickhouse.com/blog/clickhouse-gets-lazier-and-faster-introducing-lazy-materialization】,对这一特性进行了深入解读。

基于 MergeTree 表构建数据湖

贡献者:Alexey Milovidov

现在,即使 MergeTree 表存储在只读磁盘上,也能自动刷新状态,在后台发现新数据时自动加载这些数据部分。

这意味着你可以在外部托管、持续更新的数据集中运行任意数量的读取任务,非常适合用于数据共享和公开发布场景。

写入端仍然有限制——同一数据集只允许有一个写入方:

CREATE TABLE writer (...) ORDER BY ()
SETTINGS 
  table_disk = true,
  disk = disk(
      type = object_storage,
      object_storage_type = s3,
      endpoint = 'https://mybucket.s3.us-east-1.amazonaws.com/data/',
      metadata_type = plain_rewritable);

但读取端则没有限制,可以在任何位置运行任意数量的读取器:

CREATE TABLE reader (...) ORDER BY ()
SETTINGS 
  table_disk = true, 
  refresh_parts_interval = 1,
  disk = disk(
      readonly = true,
      type = object_storage,
      object_storage_type = s3,
      endpoint = 'https://mybucket.s3.us-east-1.amazonaws.com/data/',
      metadata_type = plain_rewritable);

我们来看看一个之前准备好的示例。下方这个表包含了超过 4,000 万条来自 Hacker News 的帖子数据:

CREATE TABLE hackernews_history UUID '66491946-56e3-4790-a112-d2dc3963e68a'
(
    `update_time` DateTime DEFAULT now(),
    `id` UInt32,
    `deleted` UInt8,
    `type` Enum8(
        'story' = 1, 'comment' = 2, 'poll' = 3, 'pollopt' = 4, 'job' = 5
    ),
    `by` LowCardinality(String),
    `time` DateTime,
    `text` String,
    `dead` UInt8,
    `parent` UInt32,
    `poll` UInt32,
    `kids` Array(UInt32),
    `url` String,
    `score` Int32,
    `title` String,
    `parts` Array(UInt32),
    `descendants` Int32
)
ENGINE = ReplacingMergeTree(update_time)
ORDER BY id
SETTINGS 
  refresh_parts_interval = 60, 
  disk = disk(
    readonly = true, 
    type = 's3_plain_rewritable', 
    endpoint = 'https://clicklake-test-2.s3.eu-central-1.amazonaws.com/', 
    use_environment_credentials = false
  );

你可以像查询其他表一样,直接对它运行查询:

SELECT type, count()
FROM hackernews_history
GROUP BY ALL
ORDER BY count() DESC;
┌─type────┬──count()─┐
│ comment │ 38549467 │
│ story   │  5777529 │
│ job     │    17677 │
│ pollopt │    15261 │
│ poll    │     2247 │
└─────────┴──────────┘

CPU 工作负载调度器

贡献者:Sergei Trifonov

本次版本新增了 CPU 线程调度功能,支持为特定的工作负载设置最大并发线程数。

借助这一能力,你可以在同一个 ClickHouse 集群中同时运行多种不同类型的任务,系统会根据优先级或权重,对 CPU 资源进行合理分配。例如,你可以运行较重的临时查询而不会影响到高优先级的实时报表任务。

我们先来看如何配置。首先需要定义 CPU 资源池:

CREATE RESOURCE cpu (MASTER THREAD, WORKER THREAD);

在定义了 CPU 资源之后,可以启用 max_concurrent_threads 参数,用于精细控制 CPU 分配策略。如果未定义任何 CPU 资源,ClickHouse 将默认采用服务器级别的并发控制参数(如 concurrent_threads_soft_limit_num 及相关设置)进行资源调度。

以下是文档中对线程类型的说明:

  • 主线程(Master thread):第一个启动并处理查询任务或后台操作(如数据合并或变更)的线程;

  • 工作线程(Worker thread):由主线程派生,用于执行计算密集型任务的辅助线程。

为了实现更高的响应能力,你可以为主线程和工作线程分别配置不同的资源池。

CREATE RESOURCE worker_cpu (WORKER THREAD);
CREATE RESOURCE master_cpu (MASTER THREAD);

通过执行如下查询,可以列出当前 ClickHouse 服务中定义的所有资源:

SELECT *
FROM system.resources
FORMAT Vertical;

接着,就可以基于这些资源创建不同的工作负载。

CREATE WORKLOAD all;

CREATE WORKLOAD admin IN all 
SETTINGS max_concurrent_threads = 10;

CREATE WORKLOAD production IN all 
SETTINGS max_concurrent_threads = 100;

CREATE WORKLOAD analytics IN production
SETTINGS max_concurrent_threads = 60, weight = 9;

CREATE WORKLOAD ingestion IN production;

需要注意的是,系统中只能存在一个顶层工作负载,也就是不包含 IN  子句的任务。

你也可以使用查询命令列出已有的所有工作负载:

SELECT *
FROM system.workloads
FORMAT Vertical;

最后,在运行查询时,你可以指定希望使用的工作负载类型:

SET workload = 'analytics';

EXISTS 子句支持相关子查询

贡献者:Dmitry Novik

本次版本引入了一个非常实用的新功能:EXISTS 子句现在支持相关子查询(correlated subquery)了。我们借助英国房地产数据集来看看它的用法。

下图是该数据集的表结构:

CREATE TABLE uk.uk_price_paid
(
    price UInt32,
    date Date,
    postcode1 LowCardinality(String),
    postcode2 LowCardinality(String),
    type Enum8('terraced' = 1, 'semi-detached' = 2, 'detached' = 3, 'flat' = 4, 'other' = 0),
    is_new UInt8,
    duration Enum8('freehold' = 1, 'leasehold' = 2, 'unknown' = 0),
    addr1 String,
    addr2 String,
    street LowCardinality(String),
    locality LowCardinality(String),
    town LowCardinality(String),
    district LowCardinality(String),
    county LowCardinality(String)
)
ENGINE = MergeTree
ORDER BY (postcode1, postcode2, addr1, addr2);

假设我们希望找出在 2009 年平均房价最高的地区或城镇,但需要满足两个条件:一是该地区在当年至少售出 5 套房产;二是在 2006 年,该地区至少售出过一套售价超过 100 万英镑的独立屋。

现在可以通过下面这个查询来实现这一目标:

SELECT district, town,
       round(AVG(price), 2) AS avgPrice,
       COUNT(*) AS totalSales
FROM uk.uk_price_paid p1
WHERE date BETWEEN '2009-01-01' AND '2009-12-31'
AND EXISTS (
  SELECT 1
  FROM uk.uk_price_paid p2
  WHERE p2.district = p1.district
  AND p2.town = p1.town
  AND p2.type = 'detached'
  AND p2.price > 1000000
  AND p2.date BETWEEN '2006-01-01' AND '2006-12-31'
)
GROUP BY ALL
HAVING totalSales > 5
ORDER BY avgPrice DESC
LIMIT 10
SETTINGS allow_experimental_correlated_subqueries = 1;
┌─district───────────────┬─town─────────────┬───avgPrice─┬─totalSales─┐
│ ELMBRIDGE              │ LEATHERHEAD      │  1118756.9 │         58 │
│ KENSINGTON AND CHELSEA │ LONDON           │ 1060251.76 │       1620 │
│ WOKING                 │ GUILDFORD        │     901000 │          9 │
│ CHILTERN               │ TRING            │  893333.33 │          6 │
│ ENFIELD                │ BARNET           │  891921.88 │         48 │
│ ELMBRIDGE              │ COBHAM           │   875841.6 │        202 │
│ WYCOMBE                │ HENLEY-ON-THAMES │     846300 │         10 │
│ GUILDFORD              │ GODALMING        │  831977.67 │          9 │
│ RUNNYMEDE              │ VIRGINIA WATER   │  802773.53 │         85 │
│ THREE RIVERS           │ NORTHWOOD        │  754197.22 │         36 │
└────────────────────────┴──────────────────┴────────────┴────────────┘

请注意,这个功能仍处于实验阶段,因此需要启用参数 allow_experimental_correlated_subqueries。

在第 10 行和第 11 行的子查询部分(p2)中引用了外层查询(p1)的字段。条件 p2.district = p1.district AND p2.town = p1.town 表示会为每一组地区和城镇组合分别执行一次子查询,从而形成动态的查询关系。

clickhouse-local 中支持持久化数据库

贡献者:Alexey Milovidov

在使用 clickhouse-local 工具时,现在默认数据库内容可以持久保存。

为了更直观地理解这一变化,我们先在 25.3 版本中启动 clickhouse-local:

clickhouse -m --path data

创建一个测试表:

CREATE TABLE foo (a UInt8) ORDER BY a;

退出 CLI(输入 exit;),并重新启动后,再次查询会发现表已不存在:

SHOW TABLES
    Ok.
    
    0 rows in set. Elapsed: 0.008 sec.

    再看 25.4 版本中的行为:

    clickhouse -m --path data2

    创建相同的表:

    CREATE TABLE foo (a UInt8) ORDER BY a;

    这次我们在退出并重新进入后,可以看到之前创建的表依然存在:

    SHOW TABLES
         ┌─name─┐
      1. │ foo  │
         └──────┘
      
      1 row in set. Elapsed: 0.006 sec.

      Apache Iceberg 时光回溯功能

      贡献者:Brett Hoerner、Dan Ivanik

      在最近几个版本中,ClickHouse 持续增强了对开放表格式(如 Apache Iceberg 和 Delta Lake)以及目录服务(如 Unity 和 AWS Glue)的支持。本次发布同样带来了重要进展。

      现在,ClickHouse 可以基于历史快照执行 Apache Iceberg 查询,也就是支持“时光回溯(time travel)”功能。我们还录制了一段视频,演示了如何结合 AWS Glue Catalog 使用这一特性。

      下面是一个示例,展示如何在查询中使用该功能的语法:

      CREATE DATABASE test
      ENGINE = DataLakeCatalog
      SETTINGS 
        catalog_type = 'glue', 
        region = '', 
        aws_access_key_id = '', 
        aws_secret_access_key = '';
      SELECT count()
      FROM test.`iceberg_benchmark.time_travel`
      SETTINGS iceberg_timestamp_ms = 1742497721135;

      开发者还可以参考 AWS Glue Catalog 的开发者指南【https://clickhouse.com/docs/use-cases/data-lake/glue-catalog】,获取更多示例和用法。

      表级默认压缩编码器

      贡献者:Gvoelfin

      现在可以为 MergeTree 表中的每一列设置默认压缩编码器。例如:

      CREATE TABLE t (
          time DateTime CODEC(ZSTD(3)), -- codec on a column level
          user_id UInt64, -- uses the default codec
          ...
      ) ORDER BY time
      SETTINGS default_compression_codec = 'ZSTD(1)' -- codec on a table level

      需要注意的是,自托管版本默认使用 LZ4 编码,而 ClickHouse Cloud 默认使用 ZSTD 编码。

      除了可以在单个表中设置压缩方式外,也可以通过配置文件为所有表全局指定默认压缩算法:

      config.d/compression.yaml

      compression:
          case:
              min_part_size: 1000000000 # Optional condition
              method: 'zstd'

      SSH 接口

      贡献者:George Gamezardashvili、Nikita Mikhailov

      自 ClickHouse 25.3 起,ClickHouse Server 已新增对 SSH 协议的支持,意味着用户可以直接使用任何标准 SSH 客户端连接到服务端。

      我们也已在 play.clickhouse.com 平台上启用了该功能。用户可以通过以下命令进行连接:

      ssh play@play.clickhouse.com

      该服务无需密码验证,当提示输入密码时,直接按 Enter 键即可跳过。

      平台上预置了多个数据集供用户试用。以下是一个查询示例,数据表中包含股票价格信息:

      SELECT symbol, max(price), sum(volume)
      FROM stock
      GROUP BY ALL
      ORDER BY max(price) DESC
      LIMIT 10;
          ┌─symbol─┬─max(price)─┬─sum(volume)─┐
       1. │ RBAK   │    9963.24 │ 11569148200 │
       2. │ SEB    │    1670.01 │     2382900 │
       3. │ WPO    │     996.74 │    30127600 │
       4. │ NVR    │        938 │   178289600 │
       5. │ GIW    │        767 │     1306400 │
       6. │ WTM    │      702.5 │    21839600 │
       7. │ INFY   │    670.062 │   670302700 │
       8. │ QCOM   │        659 │ 28698244000 │
       9. │ MCHXP  │        585 │       58200 │
      10. │ MTB    │     575.25 │   507431900 │
          └────────┴────────────┴─────────────┘

      征稿启示

      面向社区长期正文,文章内容包括但不限于关于 ClickHouse 的技术研究、项目实践和创新做法等。建议行文风格干货输出&图文并茂。质量合格的文章将会发布在本公众号,优秀者也有机会推荐到 ClickHouse 官网。请将文章稿件的 WORD 版本发邮件至:Tracy.Wang@clickhouse.com

      评论
      添加红包

      请填写红包祝福语或标题

      红包个数最小为10个

      红包金额最低5元

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

      抵扣说明:

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

      余额充值