博客 / 工程

ClickHouse 24.9 版本发布

author avatar
ClickHouse 团队
2024 年 10 月 4 日 - 9 分钟阅读

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

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 类型也是如此。以下文件就是这种情况

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),因为每个值都可以转换为字符串。您仍然可以让它将 id 列推断为 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 │
└──────────────────────────────┘
分享这篇文章

订阅我们的新闻通讯

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