博客 / 工程

ClickHouse Release 24.10

author avatar
ClickHouse 团队
2024 年 11 月 6 日 - 18 分钟阅读

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

ClickHouse 24.10 版本包含 25 个新功能 🌰 15 项性能优化 🐿 60 个错误修复 🎃

在此版本中,clickhouse-local 通过新的复制和计算器模式变得更加有用。可刷新的物化视图已准备好投入生产,远程文件现在可以被缓存,并且表克隆已得到简化。

新贡献者

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

以下是新贡献者的名字

Alsu Giliazova, Baitur, Baitur Ulukbekov, Damian Kula, DamianMaslanka5, Daniil Gentili, David Tsukernik, Dergousov Maxim, Diana Carroll, Faizan Patel, Hung Duong, Jiří Kozlovský, Kaushik Iska, Konstantin Vedernikov, Lionel Palacin, Mariia Khristenko, Miki Matsumoto, Oleg Galizin, Patrick Druley, SayeedKhan21, Sharath K S, Shichao, Shichao Jin, Vladimir Cherkasov, Vladimir Valerianov, Z.H., aleksey, alsu, johnnyfish, kurikuQwQ, kylhuk, lwz9103, scanhex12, sharathks118, singhksandeep25, sum12, tuanpach

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

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

clickhouse-local 简化文件转换

由 Denis Hananein 贡献

ClickHouse 有多种形式。其中一种是 clickhouse-local,它允许您使用 SQL 对本地和远程文件执行快速处理,而无需安装数据库服务器。下图显示了 ClickHouse 的变体

Google Keep Note (1).png

clickhouse-local 现在有一个新标志 —-copy,它是 SELECT * FROM table 的快捷方式。这意味着将数据从一种格式转换为另一种格式非常容易。

我们将从 datablist/sample-csv-files GitHub 存储库下载 100 万人的 CSV 文件,然后我们可以运行以下查询来创建该文件的 Parquet 版本

clickhouse -t --copy < people-1000000.csv > people.parquet

我们可以运行以下查询来探索我们的新文件

clickhouse -f PrettyCompact \
"SELECT \"Job Title\", count()
 FROM 'people.parquet'
 GROUP BY ALL
 ORDER BY count() DESC
 LIMIT 10"

    ┌─Job Title───────────────────────────────────┬─count()─┐
 1. │ Dealer                                      │    1684 │
 2. │ IT consultant                               │    1678 │
 3. │ Designer, ceramics/pottery                  │    1676 │
 4. │ Pathologist                                 │    1673 │
 5. │ Pharmacist, community                       │    1672 │
 6. │ Biochemist, clinical                        │    1669 │
 7. │ Chief Strategy Officer                      │    1663 │
 8. │ Armed forces training and education officer │    1661 │
 9. │ Archaeologist                               │    1657 │
10. │ Education officer, environmental            │    1657 │
    └─────────────────────────────────────────────┴─────────┘

如果,相反,我们想将数据从 CSV 转换为 JSON Lines 格式,我们可以执行以下操作

clickhouse -t --copy < people-1000000.csv > people.jsonl

让我们看看我们的新文件

head -n3 people.jsonl

{"Index":"1","User Id":"9E39Bfc4fdcc44e","First Name":"Diamond","Last Name":"Dudley","Sex":"Male","Email":"[email protected]","Phone":"922.460.8218x66252","Date of birth":"1970-01-01","Job Title":"Photographer"}
{"Index":"2","User Id":"32C079F2Bad7e6F","First Name":"Ethan","Last Name":"Hanson","Sex":"Female","Email":"[email protected]","Phone":"(458)005-8931x2478","Date of birth":"1985-03-08","Job Title":"Actuary"}
{"Index":"3","User Id":"a1F7faeBf5f7A3a","First Name":"Grace","Last Name":"Huerta","Sex":"Female","Email":"[email protected]","Phone":"(720)205-4521x7811","Date of birth":"1970-01-01","Job Title":"Visual merchandiser"}

clickhouse-local 计算器模式

由 Alexey Milovidov 贡献

clickhouse-local 现在也具有“计算器模式”。您可以使用 --implicit-select 标志来运行表达式,而无需 SELECT 前缀。

例如,以下表达式查找现在之前 23 分钟的时间

clickhouse --implicit-select -q "now() - INTERVAL 23 MINUTES"

2024-11-04 10:32:58

表克隆

由 Tuan Pach 贡献

想象一下,如果您可以几乎立即创建一个大型表的一对一副本,而无需额外的存储空间。这在您想对数据进行无风险实验的情况下非常有用。

使用 CLONE AS 子句,现在比以往任何时候都更容易。使用此子句与创建空表并附加源表的所有分区相同。

当我们运行克隆操作时,ClickHouse 不会为新表创建数据副本。相反,它为新表创建新部件,这些部件是到现有表部件的硬链接。

ClickHouse 中的数据部件是不可变的,这意味着如果我们在任何一个表中添加新数据或修改现有数据,另一个表都不会受到影响。

例如,假设我们有一个名为 people 的表,该表基于前面提到的 CSV 文件

CREATE TABLE people 
ORDER BY Index AS
SELECT * 
FROM 'people*.csv'
SETTINGS schema_inference_make_columns_nullable=0;

我们可以通过运行以下查询将此表克隆到另一个名为 people2 的表

CREATE TABLE people2 CLONE AS people;

这两个表现在包含相同的数据。

SELECT count()
FROM people

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

SELECT count()
FROM people2

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

但我们仍然可以独立地向它们添加数据。例如,让我们将 CSV 文件中的所有行添加到 people2 表中

INSERT INTO people2 
SELECT * 
FROM 'people*.csv';

现在,让我们计算每个表中的记录数

SELECT count()
FROM people

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

SELECT count()
FROM people2

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

客户端中的实时指标

由 Maria Khristenko、Julia Kartseva 贡献

从 ClickHouse 客户端或使用 clickhouse-local 运行查询时,我们可以通过按空格键来更细粒度地查看正在发生的事情。

例如,假设我们运行以下查询

SELECT product_category, count() AS reviews, 
       round(avg(star_rating), 2) as avg
FROM s3(
  's3://datasets-documentation/amazon_reviews/amazon_reviews_2015.snappy.parquet'
)
GROUP BY ALL
LIMIT 10;

如果我们在查询运行时按下空格键,我们将看到以下内容

然后,当查询完成时,它将显示以下统计信息

Event name                            Value
AddressesMarkedAsFailed               2
ContextLock                           32
InitialQuery                          1
QueriesWithSubqueries                 1
Query                                 1
S3Clients                             1
S3HeadObject                          2
S3ReadMicroseconds                    9.15 s
S3ReadRequestsCount                   52
S3WriteRequestsCount                  2
S3WriteRequestsErrors                 2
SchemaInferenceCacheHits              1
SchemaInferenceCacheSchemaHits        1
SelectQueriesWithSubqueries           1
SelectQuery                           1
StorageConnectionsCreated             17
StorageConnectionsElapsedMicroseconds 5.02 s
StorageConnectionsErrors              2
StorageConnectionsExpired             12
StorageConnectionsPreserved           47
StorageConnectionsReset               7
StorageConnectionsReused              35
TableFunctionExecute                  1

缓存远程文件

由 Kseniia Sumarokova 贡献

如果您运行过如下查询

SELECT
    product_category,
    count() AS reviews,
    round(avg(star_rating), 2) AS avg
FROM s3('s3://datasets-documentation/amazon_reviews/amazon_reviews_2015.snappy.parquet')
GROUP BY ALL
LIMIT 10;

您会注意到,在后续运行中,查询速度会稍微快一些,但不会快很多。

不会再这样了!从 24.10 开始,ClickHouse 提供了对直接访问的文件进行缓存的功能
以及 S3 和 Azure 上的数据湖表。

缓存条目由路径 + ETag 标识,ClickHouse 将缓存查询中引用的列的数据。要启用它,您需要在 ClickHouse 服务器配置文件中添加以下条目(此功能目前不适用于 ClickHouse Local)

   <filesystem_caches>
        <cache_for_s3>
                <path>/data/s3_cache_clickhouse</path>
            <max_size>10Gi</max_size>
        </cache_for_s3>
    </filesystem_caches>

您可以通过运行 SHOW FILESYSTEM CACHES 来检查 ClickHouse 是否已拾取您的文件系统缓存。然后,您需要在运行查询时启用缓存并提供您的缓存名称

SELECT
    product_category,
    count() AS reviews,
    round(avg(star_rating), 2) AS avg
FROM s3('s3://datasets-documentation/amazon_reviews/amazon_reviews_2015.snappy.parquet')
GROUP BY ALL
LIMIT 10
SETTINGS enable_filesystem_cache = 1, filesystem_cache_name = 'cache_for_s3'

除了查看查询时间外,您还可以通过在查询运行时按空格键来查看 S3* 实时指标。以下是不使用缓存的上述查询的指标

S3Clients                                  1
S3GetObject                                186
S3ListObjects                              2
S3ReadMicroseconds                         16.21 s
S3ReadRequestsCount                        192
S3ReadRequestsErrors                       1
S3WriteMicroseconds                        475.00 us
S3WriteRequestsCount                       1

以及使用缓存的指标

S3Clients                                 1
S3ListObjects                             2
S3ReadMicroseconds                        122.66 ms
S3ReadRequestsCount                       6
S3ReadRequestsErrors                      1
S3WriteMicroseconds                       487.00 us
S3WriteRequestsCount                      1

最大的区别是 S3GetObject 请求的数量,不使用缓存时为 186,使用缓存时为 0。

缓存使用 LRU 驱逐策略。

可刷新的物化视图已准备好投入生产

由 Michael Kolupaev 贡献

我们在 23.1224.9 发布博客文章中讨论了可刷新的物化视图,当时它仍然是一项实验性功能。

在 24.10 中,此功能支持 Replicated 数据库引擎,并且也已准备好投入生产!

查询 MongoDB 的改进

由 Kirill Nikiforov 贡献

ClickHouse 附带 50 多个 内置外部系统集成,包括 MongoDB

可以使用 MongoDB 表函数MongoDB 表引擎 从 ClickHouse 直接查询 MongoDB。后者可用于为查询远程 MongoDB 集合创建永久代理表,而表函数允许对远程 MongoDB 集合进行临时查询。

这两种集成在之前都有一些明显的限制。例如,并非所有 MongoDB 数据类型 都受支持,并且查询的 WHEREORDER BY 条件是在 ClickHouse 端应用的,首先从 MongoDB 集合读取所有未过滤和未排序的数据之后。

ClickHouse 24.10 现在提供了重构且大大改进的 MongoDB 集成支持

  • 支持所有 MongoDB 数据类型

  • 下推 WHERE 条件和 ORDER BY

  • 带有 mongodb:// 模式的连接字符串

为了演示改进的 MongoDB 集成,我们 安装 了 AWS EC2 机器上的 MongoDB 8.0 Community Edition,加载了一些 数据,并在 mongosh (MongoDB Shell) 中运行了以下命令,以查看其中一个摄取的 JSON 文档

github> db.events.aggregate([{ $sample: { size: 1 } }]);
[
  {
    _id: ObjectId('672a3659366c7681f18c5334'),
    id: '29478055921',
    type: 'PushEvent',
    actor: {
      id: 82174588,
      login: 'denys-kosyriev',
      display_login: 'denys-kosyriev',
      gravatar_id: '',
      url: 'https://api.github.com/users/denys-kosyriev',
      avatar_url: 'https://avatars.githubusercontent.com/u/82174588?'
    },
    repo: {
      id: 637899002,
      name: 'denys-kosyriev/gulp-vector',
      url: 'https://api.github.com/repos/denys-kosyriev/gulp-vector'
    },
    payload: {
      repository_id: 637899002,
      push_id: Long('13843301463'),
      size: 1,
      distinct_size: 1,
      ref: 'refs/heads/create-settings-page',
      head: 'dfa3d843b579b7d403884ff7c14b1c0100e6ba2c',
      before: '3a5211f72354fb85567179018ad559fef77eec4a',
      commits: [
        {
          sha: 'dfa3d843b579b7d403884ff7c14b1c0100e6ba2c',
          author: { email: '[email protected]', name: 'denys_kosyriev' },
          message: "feature: setting js radio-buttons 'connection' page",
          distinct: true,
          url: 'https://api.github.com/repos/denys-kosyriev/gulp-vector/commits/dfa3d843b579b7d403884ff7c14b1c0100e6ba2c'
        }
      ]
    },
    public: true,
    created_at: '2023-06-02T01:15:20Z'
  }
]

然后我们启动了一个 ClickHouse 实例,我们在 服务器配置文件 中将 <use_legacy_mongodb_integration> 设置为 0,这目前是启用重构和改进的 MongoDB 集成所必需的。

现在我们使用以下命令从上面的 MongoDB 实例查询 github 数据库中的 events 集合,我们可以在 clickhouse-client 中运行该命令

SELECT *
FROM mongodb(
    '<HOST>:<PORT>',
    'github',
    'events',
    '<USER>',
    '<PASSWORD>',
    'id String, type String, actor String')
LIMIT 1
FORMAT Vertical

Row 1:
──────
id:    26163418664
type:  WatchEvent
actor: {"id":89544871,"login":"Aziz403","display_login":"Aziz403","gravatar_id":"","url":"https:\/\/api.github.com\/users\/Aziz403","avatar_url":"https:\/\/avatars.githubusercontent.com\/u\/89544871?"}

奖励:JSON 数据类型在行动

提醒一下,由于之前实验性实现中的一些基本设计 缺陷我们从头开始为 ClickHouse 构建了一种新的强大的 JSON 数据类型

新的 JSON 类型是专门为实现 JSON 数据的高性能处理而构建的,并且在列式存储之上脱颖而出,成为 JSON 的最佳可能实现,具有以下支持

  • 动态变化的数据: 允许同一 JSON 路径的值具有不同的数据类型(可能不兼容且事先未知),而无需统一为最常见的类型,从而保留混合类型数据的完整性。

  • 高性能和密集、真正的列式存储: 将任何插入的 JSON 键路径存储和读取为本机、密集的子列,从而实现高数据压缩并保持经典类型的查询性能。

  • 可扩展性: 允许限制单独存储的子列数量,以扩展 JSON 存储,从而对 PB 级数据集进行高性能分析。

  • 调优: 允许 JSON 解析提示(JSON 路径的显式类型、应在解析期间跳过的路径等)。

虽然此版本附带了 列表 中的较小性能和可用性改进,但我们在 24.8 版本中 宣布,JSON 重写已基本完成,并且正在走向 Beta 版,我们对其实现的质量尽可能地好抱有高度信心。

ClickHouse 现在是像 MongoDB 这样的专业 文档数据库 的强大替代品。

作为奖励,我们进行了一项快速基准测试,并将 2023 年前六个月的 GitHub 事件数据(仅以 JSON 格式提供)加载到 MongoDB 8.0 Community Edition 和 ClickHouse 24.10 中,两者都在各自的 AWS EC2 m6i.8xlarge 机器上运行,该机器具有 32 个 CPU 核心、128 GB RAM、5 TB EBS gp3 卷,操作系统为 Ubuntu 24.04 LTS (“Noble”)。摄取的 GitHub 事件数据的未压缩数据大小约为 2.4 TB。

我们的用例是临时加载和分析数据,而无需预先创建任何模式或索引。例如,在 ClickHouse 中,我们创建了以下数据库和表,并使用了一个简单的 脚本 来加载数据

CREATE DATABASE github;

USE github;
SET allow_experimental_json_type = 1;

CREATE TABLE events
(
    docs JSON()
)
ENGINE = MergeTree
ORDER BY ();

加载了 2023 年前六个月的 GitHub 事件数据后,上表包含约 7 亿个 JSON 文档

SELECT count()
FROM events;

   ┌───count()─┐
1.693137012-- 693.14 million
   └───────────┘

磁盘上的大小约为 675 GiB

SELECT 
  formatReadableSize(sum(bytes_on_disk)) AS size_on_disk
FROM system.parts
WHERE active AND (database = 'github') AND (`table` = 'events')


   ┌─size_on_disk─┐
1.674.25 GiB   │
   └──────────────┘

我们可以检查其中一个存储的 JSON 文档的结构

SELECT docs
FROM events
LIMIT 1
FORMAT PrettyJSONEachRow;

{
    "docs": {
        "actor" : {
            "avatar_url" : "https:\/\/avatars.githubusercontent.com\/u\/119809980?",
            "display_login" : "ehwu106",
            "gravatar_id" : "",
            "id" : "119809980",
            "login" : "ehwu106",
            "url" : "https:\/\/api.github.com\/users\/ehwu106"
        },
        "created_at" : "2023-01-01T00:00:00Z",
        "id" : "26163418658",
        "payload" : {
            "before" : "27e76fd2920c98cf825daefa9469cb202944d96d",
            "commits" : [
                {
                    "author" : {
                        "email" : "[email protected]",
                        "name" : "Howard Wu"
                    },
                    "distinct" : 1,
                    "message" : "pushing",
                    "sha" : "01882b15808c6cc63f4075eea105de4f608e23aa",
                    "url" : "https:\/\/api.github.com\/repos\/ehwu106\/Gmail-Filter-Solution\/commits\/01882b15808c6cc63f4075eea105de4f608e23aa"
                },
                {
                    "author" : {
                        "email" : "[email protected]",
                        "name" : "hwu106"
                    },
                    "distinct" : 1,
                    "message" : "push",
                    "sha" : "8fbcb0a5be7f1ae98c620ffc445f8212da279c4b",
                    "url" : "https:\/\/api.github.com\/repos\/ehwu106\/Gmail-Filter-Solution\/commits\/8fbcb0a5be7f1ae98c620ffc445f8212da279c4b"
                }
            ],
            "distinct_size" : "2",
            "head" : "8fbcb0a5be7f1ae98c620ffc445f8212da279c4b",
            "push_id" : "12147229638",
            "ref" : "refs\/heads\/main",
            "size" : "2"
        },
        "public" : 1,
        "repo" : {
            "id" : "582174284",
            "name" : "ehwu106\/Gmail-Filter-Solution",
            "url" : "https:\/\/api.github.com\/repos\/ehwu106\/Gmail-Filter-Solution"
        },
        "type" : "PushEvent"
    }
}

对于 MongoDB,我们使用了类似的 脚本 将相同的数据集加载到集合中(没有任何额外的索引或模式提示),我们使用 mongosh 中的命令检查存储的 JSON 文档的数量和磁盘上的大小

github> db.events.stats();
...
count: 693137012,
storageSize: 746628136960

文档计数与 ClickHouse 中的相同,存储大小略大,为 695.35 GiB。

我们还可以检查其中一个存储的 JSON 文档的结构

github> db.events.aggregate([{ $sample: { size: 1 } }]);
[
  {
    _id: ObjectId('672ab1430e44c2d6ce0433ee'),
    id: '28105983813',
    type: 'DeleteEvent',
    actor: {
      id: 10810283,
      login: 'direwolf-github',
      display_login: 'direwolf-github',
      gravatar_id: '',
      url: 'https://api.github.com/users/direwolf-github',
      avatar_url: 'https://avatars.githubusercontent.com/u/10810283?'
    },
    repo: {
      id: 183051410,
      name: 'direwolf-github/my-app',
      url: 'https://api.github.com/repos/direwolf-github/my-app'
    },
    payload: { ref: 'branch-58838bda', ref_type: 'branch', pusher_type: 'user' },
    public: true,
    created_at: '2023-03-31T00:43:36Z'
  }
]

现在我们想要分析数据集并获得不同 GitHub 事件类型的概述,并按其文档计数对其进行排名。在 ClickHouse 中,可以使用简单的聚合 SQL 查询来完成此操作

SELECT
    docs.type,
    count() AS count
FROM events
GROUP BY docs.type
ORDER BY count DESC

    ┌─docs.type─────────────────────┬─────count─┐
 1. │ PushEvent                     │ 3781085382. │ CreateEvent                   │  950543423. │ PullRequestEvent              │  555786424. │ WatchEvent                    │  412694995. │ IssueCommentEvent             │  329856386. │ DeleteEvent                   │  223954847. │ PullRequestReviewEvent        │  170298898. │ IssuesEvent                   │  142361899. │ PullRequestReviewCommentEvent │  1028559610. │ ForkEvent                     │   992648511. │ CommitCommentEvent            │   656945512. │ ReleaseEvent                  │   380453913. │ PublicEvent                   │   235255314. │ MemberEvent                   │   230402015. │ GollumEvent                   │   1235200 │
    └───────────────────────────────┴───────────┘

15 rows in set. Elapsed: 7.324 sec. Processed 693.14 million rows, 20.18 GB (94.63 million rows/s., 2.76 GB/s.)
Peak memory usage: 7.33 MiB.

该查询聚合并排序完整数据集(约 7 亿个 JSON 文档)。查询的运行时为 7.3 秒,峰值内存使用量为 7.33 MiB。如此低的内存使用量归因于 ClickHouse 的 真正的列式存储,用于 JSON 文档,从而可以独立访问 JSON 路径的子列。此外,ClickHouse 仅检索查询所需的列。在我们的示例中,它仅从 docs.type 列读取、聚合和排序数据。另请注意查询吞吐量为 9400 万行/秒和 2.76 GB/秒。

在 MongoDB 中,聚合管道 是进行聚合的推荐方式。我们在 MongoDB 中运行了一个聚合管道,它等效于上面来自 ClickHouse SQL 查询

github> start = new Date();
ISODate('2024-11-06T09:33:11.295Z')
github> db.events.aggregate([
{
  $group: {
    _id: "$type",       // Group by docs.type
    count: { $sum: 1 }  // Count each occurrence
  }
},
{
  $sort: { count: -1 }  // Sort by count in descending order
},
{
  $project: {  // Project the fields to match SQL output
    type: "$_id",
    count: 1,
    _id: 0
  }
}
]);

[
  { count: 378108538, type: 'PushEvent' },
  { count: 95054342, type: 'CreateEvent' },
  { count: 55578642, type: 'PullRequestEvent' },
  { count: 41269499, type: 'WatchEvent' },
  { count: 32985638, type: 'IssueCommentEvent' },
  { count: 22395484, type: 'DeleteEvent' },
  { count: 17030832, type: 'PullRequestReviewEvent' },
  { count: 14236189, type: 'IssuesEvent' },
  { count: 10285596, type: 'PullRequestReviewCommentEvent' },
  { count: 9926485, type: 'ForkEvent' },
  { count: 6569455, type: 'CommitCommentEvent' },
  { count: 3804539, type: 'ReleaseEvent' },
  { count: 2352553, type: 'PublicEvent' },
  { count: 2304020, type: 'MemberEvent' },
  { count: 1235200, type: 'GollumEvent' }
]
github> print(EJSON.stringify({t: new Date().getTime() - start.getTime()}));
{"t":13779342}

在 MongoDB 上(与 ClickHouse 在完全相同的硬件上运行)使用相同数据集的查询运行时为 1377934 毫秒,即约 4 小时,比 ClickHouse 慢约 2000 倍。

默认情况下(对于其 WiredTiger 存储引擎),MongoDB 将保留 50% 的可用内存。在我们的测试机器上,这是约 60 GB(可用 128 GB 的一半),我们可以通过 top 验证这一点。与 ClickHouse 相比,MongoDB 不直接跟踪其引擎内查询的峰值内存消耗。ClickHouse 服务器进程需要大约 1 GB 的 RAM,加上执行查询的峰值内存使用量。总而言之,对于运行我们的测试查询,MongoDB 的内存消耗比 ClickHouse 的内存使用量高出约 7000 倍。

分享这篇文章

订阅我们的新闻通讯

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