又一个月过去了,这意味着又到了发布新版本的时候了!
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 的变体
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.12 和 24.9 发布博客文章中讨论了可刷新的物化视图,当时它仍然是一项实验性功能。
在 24.10 中,此功能支持 Replicated 数据库引擎,并且也已准备好投入生产!
查询 MongoDB 的改进
由 Kirill Nikiforov 贡献
ClickHouse 附带 50 多个 内置外部系统集成,包括 MongoDB。
可以使用 MongoDB 表函数 或 MongoDB 表引擎 从 ClickHouse 直接查询 MongoDB。后者可用于为查询远程 MongoDB 集合创建永久代理表,而表函数允许对远程 MongoDB 集合进行临时查询。
这两种集成在之前都有一些明显的限制。例如,并非所有 MongoDB 数据类型 都受支持,并且查询的 WHERE
和 ORDER 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 │ 378108538 │
2. │ CreateEvent │ 95054342 │
3. │ PullRequestEvent │ 55578642 │
4. │ WatchEvent │ 41269499 │
5. │ IssueCommentEvent │ 32985638 │
6. │ DeleteEvent │ 22395484 │
7. │ PullRequestReviewEvent │ 17029889 │
8. │ IssuesEvent │ 14236189 │
9. │ PullRequestReviewCommentEvent │ 10285596 │
10. │ ForkEvent │ 9926485 │
11. │ CommitCommentEvent │ 6569455 │
12. │ ReleaseEvent │ 3804539 │
13. │ PublicEvent │ 2352553 │
14. │ MemberEvent │ 2304020 │
15. │ 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 倍。