DoubleCloud 即将停止服务。迁移到 ClickHouse 并享受限时免费迁移服务。立即联系我们 ->->

博客 / 工程

ClickHouse 24.9 版本发布

author avatar
ClickHouse 团队
2024年10月4日

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

ClickHouse 24.9 版本包含 **23 个新特性** 🎁 **14 项性能优化** 🛷 **76 个错误修复** 🐛

在本版本中,我们为可刷新物化视图添加了 APPEND 子句,为 JSON 数据类型添加了新的函数,并且 Variant 类型可以由自动模式推断返回。

新贡献者

一如既往,我们对 24.9 版本的所有新贡献者表示热烈的欢迎!ClickHouse 的流行在很大程度上归功于社区的贡献。看到社区不断壮大,我们深感欣慰。

以下是新贡献者的姓名列表

1on, Alexey Olshanskiy, Alexis Arnaud, Austin Bruch, Denis Hananein, Dergousov, Gabriel Mendes, Konstantin Smirnov, Kruglov Kirill, Marco Vilas Boas, Matt Woenker, Maxim Dergousov, Michal Tabaszewski, NikBarykin, Oleksandr, Pedro Ferreira, Rodrigo Garcia, Samuel Warfield, Sergey (Finn) Gnezdilov, Tuan Pham Anh, Zhigao Hong, baolin.hbl, gao chuan, haozelong, imddba, kruglov, leonkozlowski, m4xxx1m, marco-vb, megao, mmav, neoman36, okunev, siyuan

提示:如果您好奇我们如何生成此列表……请点击此处

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

可刷新物化视图的 APPEND 功能

由 Michael Kolupaev 贡献

可刷新物化视图 是物化视图的一种实验版本,用于存储查询结果以供以后快速检索。在本版本中,我们添加了 APPEND 功能,这意味着新行将添加到表的末尾,而不是替换整个视图。

此功能的一个用途是捕获某个时间点的值快照。例如,假设我们有一个 events 表,它由来自 Redpanda、Kafka 或其他流数据平台的消息流填充。

SELECT *
FROM events
LIMIT 10

Query id: 7662bc39-aaf9-42bd-b6c7-bc94f2881036

┌──────────────────ts─┬─uuid─┬─count─┐
│ 2008-08-06 17:07:190eb  │   547 │
│ 2008-08-06 17:07:1960b  │   148 │
│ 2008-08-06 17:07:19106750 │
│ 2008-08-06 17:07:19398875 │
│ 2008-08-06 17:07:19 │ ca0  │   318 │
│ 2008-08-06 17:07:196ba  │   105 │
│ 2008-08-06 17:07:19 │ df9  │   422 │
│ 2008-08-06 17:07:19 │ a71  │   991 │
│ 2008-08-06 17:07:193a2  │   495 │
│ 2008-08-06 17:07:19598238 │
└─────────────────────┴──────┴───────┘

此数据集在 uuid 列中有 4096 个值,我们可以编写以下查询来查找具有最高总计数的值

SELECT
    uuid,
    sum(count) AS count
FROM events
GROUP BY ALL
ORDER BY count DESC
LIMIT 10

┌─uuid─┬───count─┐
│ c6f  │ 5676468 │
│ 9515669731 │
│ 6a6  │ 5664552 │
│ b06  │ 5662036 │
│ 0ca  │ 5658580 │
│ 2cd  │ 5657182 │
│ 32a  │ 5656475 │
│ ffe  │ 5653952 │
│ f33  │ 5653783 │
│ c5b  │ 5649936 │
└──────┴─────────┘

假设我们希望每 10 秒捕获每个 uuid 的计数并将其存储到一个名为 events_snapshot 的新表中。events_snapshot 的模式如下所示

CREATE TABLE events_snapshot (
    ts DateTime32,
    uuid String,
    count UInt64
) 
ENGINE = MergeTree 
ORDER BY uuid;

然后,我们可以创建一个可刷新物化视图来填充此表

SET allow_experimental_refreshable_materialized_view=1;

CREATE MATERIALIZED VIEW events_snapshot_mv
REFRESH EVERY 10 SECOND APPEND TO events_snapshot
AS SELECT
    now() AS ts,
    uuid,
    sum(count) AS count
FROM events
GROUP BY ALL;

然后,我们可以查询 events_snapshot 以获取特定 uuid 随时间的计数

SELECT *
FROM events_snapshot
WHERE uuid = 'fff'
ORDER BY ts ASC
FORMAT PrettyCompactMonoBlock

┌──────────────────ts─┬─uuid─┬───count─┐
│ 2024-10-01 16:12:56 │ fff  │ 5424711 │
│ 2024-10-01 16:13:00 │ fff  │ 5424711 │
│ 2024-10-01 16:13:10 │ fff  │ 5424711 │
│ 2024-10-01 16:13:20 │ fff  │ 5424711 │
│ 2024-10-01 16:13:30 │ fff  │ 5674669 │
│ 2024-10-01 16:13:40 │ fff  │ 5947912 │
│ 2024-10-01 16:13:50 │ fff  │ 6203361 │
│ 2024-10-01 16:14:00 │ fff  │ 6501695 │
└─────────────────────┴──────┴─────────┘

模式推断中的 Variant 类型

由 Shaun Struwig 贡献

ClickHouse 现在支持自动使用 Variable 数据类型进行模式推断。此功能默认情况下处于禁用状态,但可以通过设置 input_format_try_infer_variants 来启用。

让我们看看在读取以下文件时它是如何工作的

data1.json

{"id": [1], "name": "Mark"}
{"id": "agerty", "name": "Dale"}

在第一行中,id 字段是整数数组,在第二行中是字符串。让我们查询该文件并返回 id 列的类型

select *, toTypeName(id)
FROM file('data1.json')
SETTINGS input_format_try_infer_variants=1;

┌─id─────┬─name─┬─toTypeName(id)──────────────────────────┐
│ [1]    │ Mark │ Variant(Array(Nullable(Int64)), String) │
│ agerty │ Dale │ Variant(Array(Nullable(Int64)), String) │
└────────┴──────┴─────────────────────────────────────────┘

如果我们在不设置 input_format_try_infer_variants=1 的情况下执行该查询,我们将看到以下错误消息

Received exception:
Code: 636. DB::Exception: The table structure cannot be extracted from a JSON format file. Error:
Code: 53. DB::Exception: Automatically defined type String for column 'id' in row 1 differs from type defined by previous rows: Array(Int64). You can specify the type for this column using setting schema_inference_hints. (TYPE_MISMATCH) (version 24.9.1.3278 (official build)).
You can specify the structure manually: (in file/path/to/24.9/data1.json). (CANNOT_EXTRACT_TABLE_STRUCTURE)

请记住,Variant 数据类型不会总是在您希望(甚至期望)推断的位置被推断。例如,如果 id 字段中的值可以转换为 String,即使可以推断出 Variant 类型,推断的类型也将是 String。以下文件就是这种情况

data2.json

{"id": 1, "name": "Mark"}
{"id": "agerty", "name": "Dale"}
{"id": "2021-01-04", "name": "Tom"}

如果我们运行以下查询

select *, toTypeName(id)
FROM file('data2.json')
SETTINGS input_format_try_infer_variants=1;

┌─id─────────┬─name─┬─toTypeName(id)───┐
│ 1          │ Mark │ Nullable(String) │
│ agerty     │ Dale │ Nullable(String) │
│ 2021-01-04 │ Tom  │ Nullable(String) │
└────────────┴──────┴──────────────────┘

id 列被推断为 Nullable(String),因为每个值都可以转换为字符串。您仍然可以将其推断为 Variant,但您需要提供提示

SET allow_experimental_variant_type=1;

SELECT *, toTypeName(id) 
FROM  file('data2.json') 
SETTINGS schema_inference_hints='id Variant(String, Int64, Date)';

┌─id─────────┬─name─┬─toTypeName(id)───────────────┐
│ 1          │ Mark │ Variant(Date, Int64, String) │
│ agerty     │ Dale │ Variant(Date, Int64, String) │
│ 2021-01-04 │ Tom  │ Variant(Date, Int64, String) │
└────────────┴──────┴──────────────────────────────┘

分析 JSON 的聚合函数

由 Pavel Kruglov 贡献

24.8 版本发布文章中,我们了解了新的 JSON 数据类型。此版本提供了更多用于操作 JSONDynamic 数据类型中数据的函数。让我们看看如何在以下示例数据集中使用它们

data3.json

{"id": 1, "name": "Mark"}
{"id": "agerty", "name": "Dale"}
{"id": "2021-01-04", "name": "Tom"}
{"id": ["1", 2, "3"], "name": "Alexey", "location": "Netherlands"}

我们有 distinctJSONPaths 函数,它返回不同的 JSON 路径。

SELECT distinctJSONPaths(json)
FROM file('data3.json', JSONAsObject)
FORMAT Vertical;

Row 1:
──────
distinctJSONPaths(json): ['id','location','location.city','location.country','name']

如果您想返回类型,distinctJSONPathsAndTypes 可以做到这一点

SELECT distinctJSONPathsAndTypes(json)
FROM file('data3.json', JSONAsObject)
FORMAT Vertical;

Row 1:
──────
distinctJSONPathsAndTypes(json): {'id':['Array(Nullable(String))','Int64','String'],'location':['String'],'location.city':['String'],'location.country':['String'],'name':['String']}

最后,我们有 distinctDynamicTypes,它返回 Dynamic 列的不同类型。

SELECT distinctDynamicTypes(json.id)
FROM file('data3.json', JSONAsObject)
FORMAT Vertical

Row 1:
──────
distinctDynamicTypes(json.id): ['Array(Nullable(String))','Int64','String']

URL 引擎的 _headers 列

由 Flynn 贡献

当您查询 url 表函数时,您现在可以通过 _headers 虚拟列访问响应标头

SELECT _headers
FROM url(
'https://en.wikipedia.org/w/api.php?action=query&list=recentchanges&rcprop=title%7Cids%7Csizes%7Cflags%7Cuser%7Cuserid%7Ctimestamp&format=json&rcdir=newer'
)
LIMIT 1
FORMAT Vertical;


Row 1:
──────
_headers: {'accept-ranges':'bytes','age':'0','cache-control':'private, must-revalidate, max-age=0','content-disposition':'inline; filename=api-result.json','content-type':'application/json; charset=utf-8','date':'Tue, 01 Oct 2024 15:32:59 GMT','nel':'{ "report_to": "wm_nel", "max_age": 604800, "failure_fraction": 0.05, "success_fraction": 0.0}','report-to':'{ "group": "wm_nel", "max_age": 604800, "endpoints": [{ "url": "https://intake-logging.wikimedia.org/v1/events?stream=w3c.reportingapi.network_error&schema_uri=/w3c/reportingapi/network_error/1.0.0" }] }','server':'mw-api-ext.codfw.main-54d5bc66d9-98km5','server-timing':'cache;desc="pass", host;desc="cp3067"','set-cookie':'WMF-Last-Access=01-Oct-2024;Path=/;HttpOnly;secure;Expires=Sat, 02 Nov 2024 12:00:00 GMT','strict-transport-security':'max-age=106384710; includeSubDomains; preload','transfer-encoding':'chunked','vary':'Accept-Encoding,Treat-as-Untrusted,X-Forwarded-Proto,Cookie,Authorization','x-cache':'cp3067 miss, cp3067 pass','x-cache-status':'pass','x-client-ip':'82.35.72.115','x-content-type-options':'nosniff','x-frame-options':'DENY'}

overlay 函数

如果您需要用另一个字符串替换字符串片段,那么使用 overlay 函数会更容易。您提供初始字符串、替换字符串,然后提供替换字符串开始的索引以及要替换的字符数。

我们可以使用此函数确保每个人都知道chDB也很酷!

SELECT overlay('ClickHouse is cool', 'and chDB are', 12, 2) AS res

┌─res──────────────────────────┐
│ ClickHouse and chDB are cool │
└──────────────────────────────┘
分享此文章

订阅我们的新闻通讯

随时了解功能发布、产品路线图、支持和云产品信息!
正在加载表单…
关注我们
Twitter imageSlack imageGitHub image
Telegram imageMeetup imageRss image