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

博客 / 工程

ClickHouse 24.4 版本发布

author avatar
ClickHouse 团队
2024 年 5 月 5 日

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

ClickHouse 24.3 版本包含 **13 个新特性** 🎁 **16 项性能优化** 🛷 **65 个错误修复** 🐛

新贡献者

一如既往,我们向 24.4 版本的所有新贡献者表示热烈的欢迎!ClickHouse 的受欢迎程度,在很大程度上归功于社区贡献者的努力。看到社区不断壮大,我们感到无比欣慰。

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

Alexey Katsman、Anita Hammer、Arnaud Rocher、Chandre Van Der Westhuizen、Eduard Karacharov、Eliot Hautefeuille、Igor Markelov、Ilya Andreev、Jhonso7393、Joseph Redfern、Josh Rodriguez、Kirill、KrJin、Maciej Bak、Murat Khairulin、Paweł Kudzia、Tristan、dilet6298、loselarry

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

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

递归 CTE

由 Maksim Kita 贡献

SQL:1999 引入了递归公用表表达式 (CTE) 用于层次查询,使 SQL 成为了一种图灵完备的编程语言。

到目前为止,ClickHouse 通过利用分层字典来支持层次查询。凭借我们新的查询分析和优化基础设施,现在默认启用,我们终于具备了引入像递归 CTE 这样期待已久且功能强大的特性的所有条件。

ClickHouse 递归 CTE 具有 标准的 SQL:1999 语法,并且通过了所有 PostgreSQL 递归 CTE 测试。此外,ClickHouse 现在对递归 CTE 的支持比 PostgreSQL 更好。在 CTE 的 UNION ALL 子句的底部部分,可以指定多个(任意复杂的)查询,可以多次引用 CTE 基本表等等。

递归 CTE 可以优雅而简单地解决层次结构问题。例如,它们可以轻松回答层次数据模型(例如树和图)的可达性问题。

具体来说,递归 CTE 可以计算关系的传递闭包。以伦敦地铁的线路连接作为二元关系示例,您可以想象所有直接连接的地铁站的集合:Oxford Circus -> Bond StreetBond Street -> Marble ArchMarble Arch -> Lancaster Gate,等等。这些连接的传递闭包包括这些站点之间所有可能的连接,例如Oxford Circus -> Lancaster GateOxford Circus -> Marble Arch,等等。

为了演示这一点,我们使用了数据集的改编版本,该数据集模拟了所有伦敦地铁连接,其中每个条目代表两个直接连接的站点。然后,我们可以使用递归 CTE 来轻松回答如下问题

牛津马戏团站出发,乘坐中央线,最多可以到达哪些站点(不超过 5 站)?

我们使用中央线站点地图的截图对此进行可视化

unnamed2.png

我们创建一个 ClickHouse 表来存储伦敦地铁连接数据集

CREATE OR REPLACE TABLE Connections (
    Station_1 String,
    Station_2 String,
    Line String,
    PRIMARY KEY(Line, Station_1, Station_2)
);

细心的读者会注意到,我们在上面的 DDL 语句中没有指定表引擎(因为 ClickHouse 24.3 版本允许这样做),并在列定义中使用了 PRIMARY KEY 语法(因为 ClickHouse 23.7 版本允许这样做)。这样一来,不仅递归 CTE,而且我们的 ClickHouse 表 DDL 语法都符合 SQL 标准。

通过利用url 表函数自动模式推断,我们将数据集直接加载到我们的表中

INSERT INTO Connections
SELECT * FROM url('https://datasets-documentation.s3.eu-west-3.amazonaws.com/london_underground/london_connections.csv')

加载后的数据如下所示

SELECT
    *
FROM Connections
WHERE Line = 'Central Line'
ORDER BY Station_1, Station_2
LIMIT 10;

    ┌─Station_1──────┬─Station_2────────┬─Line─────────┐
 1. │ Bank           │ Liverpool Street │ Central Line │
 2. │ Bank           │ St. Paul's       │ Central Line │
 3. │ Barkingside    │ Fairlop          │ Central Line │
 4. │ Barkingside    │ Newbury Park     │ Central Line │
 5. │ Bethnal Green  │ Liverpool Street │ Central Line │
 6. │ Bethnal Green  │ Mile End         │ Central Line │
 7. │ Bond Street    │ Marble Arch      │ Central Line │
 8. │ Bond Street    │ Oxford Circus    │ Central Line │
 9. │ Buckhurst Hill │ Loughton         │ Central Line │
10. │ Buckhurst Hill │ Woodford         │ Central Line │
    └────────────────┴──────────────────┴──────────────┘

现在,我们使用递归 CTE 来回答上述问题

WITH RECURSIVE Reachable_Stations AS
(
    SELECT Station_1, Station_2, Line, 1 AS stops
    FROM Connections
    WHERE Line = 'Central Line'
      AND Station_1 = 'Oxford Circus'
    UNION ALL
    SELECT rs.Station_1, c.Station_2, c.Line, rs.stops + 1 AS stops
    FROM Reachable_Stations AS rs, Connections AS c
    WHERE rs.Line = c.Line
      AND rs.Station_2 = c.Station_1
      AND rs.stops < 5
)
SELECT DISTINCT (Station_1, Station_2, stops) AS connections
FROM Reachable_Stations
ORDER BY stops ASC;

结果如下

    ┌─connections────────────────────────────────┐
 1. │ ('Oxford Circus','Bond Street',1)          │
 2. │ ('Oxford Circus','Tottenham Court Road',1) │
 3. │ ('Oxford Circus','Marble Arch',2)          │
 4. │ ('Oxford Circus','Oxford Circus',2)        │
 5. │ ('Oxford Circus','Holborn',2)              │
 6. │ ('Oxford Circus','Bond Street',3)          │
 7. │ ('Oxford Circus','Lancaster Gate',3)       │
 8. │ ('Oxford Circus','Tottenham Court Road',3) │
 9. │ ('Oxford Circus','Chancery Lane',3)        │
10. │ ('Oxford Circus','Marble Arch',4)          │
11. │ ('Oxford Circus','Oxford Circus',4)        │
12. │ ('Oxford Circus','Queensway',4)            │
13. │ ('Oxford Circus','Holborn',4)              │
14. │ ('Oxford Circus','St. Paul\'s',4)          │
15. │ ('Oxford Circus','Bond Street',5)          │
16. │ ('Oxford Circus','Lancaster Gate',5)       │
17. │ ('Oxford Circus','Tottenham Court Road',5) │
18. │ ('Oxford Circus','Notting Hill Gate',5)    │
19. │ ('Oxford Circus','Chancery Lane',5)        │
20. │ ('Oxford Circus','Bank',5)                 │
    └────────────────────────────────────────────┘

递归 CTE 具有简单的基于迭代的执行逻辑,其行为类似于递归自连接(self-self-...-self-join),一旦找不到新的连接伙伴或满足中止条件,就会停止自连接。为此,我们上面的 CTE 从执行 UNION ALL 子句的顶部部分开始,查询我们的 Connections 表以查找中央线上与牛津马戏团站直接连接的所有站点。这将返回一个绑定到 Reachable_Stations 标识符的表,如下所示

 Initial Reachable_Stations table content
 ┌─Station_1─────┬─Station_2────────────┐
 │ Oxford Circus │ Bond Street          │
 │ Oxford Circus │ Tottenham Court Road │
 └───────────────┴──────────────────────┘

从现在开始,将只执行 CTE 的 UNION ALL 子句的底部部分(递归地)

Reachable_Stations 与 Connections 表连接以查找 Connections 表中的以下连接伙伴,其 Station_1 值与 Reachable_Stations 的 Station_2 值匹配

Connections table join partners

┌─Station_1────────────┬─Station_2─────┐
│ Bond Street          │ Marble Arch   │
│ Bond Street          │ Oxford Circus │
│ Tottenham Court Road │ Holborn       │
│ Tottenham Court Road │ Oxford Circus │
└──────────────────────┴───────────────┘

通过 UNION ALL 子句,这些连接伙伴被添加到 Reachable_Stations 表中(Station_1 列被替换为牛津马戏团),并且我们递归 CTE 的第一次迭代完成。在下次迭代中,通过执行 CTE 的 UNION ALL 子句的底部部分,Reachable_Stations 再次与 Connections 表连接以识别(并添加到 Reachable_Stations)Connections 表中所有新的连接伙伴,其 Station_1 值与 Reachable_Stations 的 Station_2 值匹配。这些迭代将持续进行,直到找不到新的连接伙伴或满足停止条件。在我们上面的查询中,我们使用 stops 计数器在达到从起始站指定的允许停止次数时中止 CTE 的迭代循环。

请注意,结果将牛津马戏团列为从牛津马戏团出发,经过 2 站和 4 站可到达的站点。从理论上讲这是正确的,但在实践中并不实用,这是因为我们的查询不考虑任何方向或循环。我们将其留作读者的有趣练习。

作为奖励问题,我们想知道从中央线的牛津马戏团站到斯特拉特福德站需要多少站。我们再次使用中央线地图对其进行可视化

 (5).png

为此,我们只需要修改递归 CTE 的中止条件(一旦将目标站为斯特拉特福德的连接伙伴添加到 CTE 表中,就停止 CTE 的连接迭代)

WITH RECURSIVE Reachable_Stations AS
(
    SELECT Station_1, Station_2, Line, 1 AS stops
    FROM Connections
    WHERE Line = 'Central Line'
      AND Station_1 = 'Oxford Circus'
  UNION ALL
    SELECT rs.Station_1 c.Station_2, c.Line, rs.stops + 1 AS stops
    FROM Reachable_Stations AS rs, Connections AS c
    WHERE rs.Line = c.Line
      AND rs.Station_2 = c.Station_1
      AND 'Stratford' NOT IN (SELECT Station_2 FROM Reachable_Stations)
)
SELECT max(stops) as stops
FROM Reachable_Stations;

结果显示需要 9 站,这与上面中央线的地图规划相符

   ┌─stops─┐
1. │     9 │
   └───────┘

递归 CTE 可以轻松地回答关于此数据集更有趣的问题。例如,数据集原始版本中的相对连接时间可用于发现从 Oxford Circus 站到 Heathrow Airport 站最快(且跨越地铁线路)的连接方式。敬请关注后续单独文章中对此问题的解答。

QUALIFY

由 Maksim Kita 贡献

此版本添加的另一个功能是 QUALIFY 子句,它允许我们根据窗口函数的值进行过滤。

我们将借助 窗口函数 - 排名 示例了解如何使用它。该数据集包含假设的足球运动员及其薪资。我们可以像这样将其导入 ClickHouse

CREATE TABLE salaries ORDER BY team AS
FROM url('https://raw.githubusercontent.com/ClickHouse/examples/main/LearnClickHouseWithMark/WindowFunctions-Aggregation/data/salaries.csv')
SELECT * EXCEPT (weeklySalary), weeklySalary AS salary
SETTINGS schema_inference_make_columns_nullable=0;

让我们快速查看一下 salaries 表中的数据。

SELECT * FROM salaries LIMIT 5;
   ┌─team──────────────┬─player───────────┬─position─┬─salary─┐
1. │ Aaronbury Seekers │ David Morton     │ D        │  63014 │
2. │ Aaronbury Seekers │ Edwin Houston    │ D        │  51751 │
3. │ Aaronbury Seekers │ Stephen Griffith │ M        │ 181825 │
4. │ Aaronbury Seekers │ Douglas Clay     │ F        │  73436 │
5. │ Aaronbury Seekers │ Joel Mendoza     │ D        │ 257848 │
   └───────────────────┴──────────────────┴──────────┴────────┘

接下来,让我们计算每个球员按位置的薪资排名。即,与在相同位置比赛的人相比,他们的薪资是多少?

SELECT player, team, position AS pos, salary,
       rank() OVER (PARTITION BY position ORDER BY salary DESC) AS posRank
FROM salaries
ORDER BY salary DESC
LIMIT 5
   ┌─player──────────┬─team────────────────────┬─pos─┬─salary─┬─posRank─┐
1. │ Robert Griffin  │ North Pamela Trojans    │ GK  │ 399999 │       1 │
2. │ Scott Chavez    │ Maryhaven Generals      │ M   │ 399998 │       1 │
3. │ Dan Conner      │ Michaelborough Rogues   │ M   │ 399998 │       1 │
4. │ Nathan Thompson │ Jimmyville Legionnaires │ D   │ 399998 │       1 │
5. │ Benjamin Cline  │ Stephaniemouth Trojans  │ D   │ 399998 │       1 │
   └─────────────────┴─────────────────────────┴─────┴────────┴─────────┘

假设我们想过滤 posRank 以仅返回按位置薪资排名前三的球员。我们可能会尝试添加 WHERE 子句来实现此目的。

SELECT player, team, position AS pos, salary,
       rank() OVER (PARTITION BY position ORDER BY salary DESC) AS posRank
FROM salaries
WHERE posRank <= 3
ORDER BY salary DESC
LIMIT 5
Received exception:
Code: 184. DB::Exception: Window function rank() OVER (PARTITION BY position ORDER BY salary DESC) AS posRank is found in WHERE in query. (ILLEGAL_AGGREGATION)

我们无法这样做,因为 WHERE 子句在窗口函数评估之前运行。在 24.4 版本之前,我们可以通过引入 CTE 来解决此问题。

WITH salaryRankings AS
    (
        SELECT player, 
               if(
                 length(team) <=25, 
                 team, 
                 concat(substring(team, 5), 1, '...')
               ) AS team, 
               position AS pos, salary,
               rank() OVER (
                 PARTITION BY position 
                 ORDER BY salary DESC
               ) AS posRank
        FROM salaries
        ORDER BY salary DESC
    )
SELECT *
FROM salaryRankings
WHERE posRank <= 3
    ┌─player────────────┬─team────────────────────┬─pos─┬─salary─┬─posRank─┐
 1. │ Robert Griffin    │ North Pamela Trojans    │ GK  │ 399999 │       1 │
 2. │ Scott Chavez      │ Maryhaven Generals      │ M   │ 399998 │       1 │
 3. │ Dan Conner        │ Michaelborough Rogue... │ M   │ 399998 │       1 │
 4. │ Benjamin Cline    │ Stephaniemouth Troja... │ D   │ 399998 │       1 │
 5. │ Nathan Thompson   │ Jimmyville Legionnai... │ D   │ 399998 │       1 │
 6. │ William Rubio     │ Nobleview Sages         │ M   │ 399997 │       3 │
 7. │ Juan Bird         │ North Krystal Knight... │ GK  │ 399986 │       2 │
 8. │ John Lewis        │ Andreaberg Necromanc... │ D   │ 399985 │       3 │
 9. │ Michael Holloway  │ Alyssaborough Sages     │ GK  │ 399984 │       3 │
10. │ Larry Buchanan    │ Eddieshire Discovere... │ F   │ 399973 │       1 │
11. │ Alexis Valenzuela │ Aaronport Crusaders     │ F   │ 399972 │       2 │
12. │ Mark Villegas     │ East Michaelborough ... │ F   │ 399972 │       2 │
    └───────────────────┴─────────────────────────┴─────┴────────┴─────────┘

此查询有效,但相当笨拙。现在我们有了 QUALIFY 子句,我们可以在不引入 CTE 的情况下过滤数据,如下所示。

SELECT player, team, position AS pos, salary,
       rank() OVER (PARTITION BY position ORDER BY salary DESC) AS posRank
FROM salaries
QUALIFY posRank <= 3
ORDER BY salary DESC;

我们将获得与之前相同的结果。

连接性能改进

由 Maksim Kita 贡献

对于非常具体的 JOIN 使用场景,也有一些性能改进。

第一个是更好的谓词下推,当分析器确定何时可以将过滤器条件应用于 JOIN 的两侧时。

让我们来看一个使用 OpenSky 数据集 的示例,该数据集包含 2019-2021 年的空中交通数据。我们想要获取经过旧金山的十个航班的列表,我们可以使用以下查询来实现。

SELECT
    l.origin,
    r.destination AS dest,
    firstseen,
    lastseen
FROM opensky AS l
INNER JOIN opensky AS r ON l.destination = r.origin
WHERE notEmpty(l.origin) AND notEmpty(r.destination) AND (r.origin = 'KSFO')
LIMIT 10
SETTINGS optimize_move_to_prewhere = 0

我们禁用了 optimize_move_to_prewhere,以便 ClickHouse 不执行其他优化,这将阻止我们看到 JOIN 改进带来的好处。如果我们在 24.3 上运行此查询,我们将看到以下输出。

    ┌─origin─┬─dest─┬───────────firstseen─┬────────────lastseen─┐
 1.00WA   │ 00CL │ 2019-10-14 21:03:192019-10-14 22:42:012.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:013.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:014.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:015.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:016.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:017.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:018.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:019.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:0110.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:01 │
    └────────┴──────┴─────────────────────┴─────────────────────┘

10 rows in set. Elapsed: 0.656 sec. Processed 15.59 million rows, 451.90 MB (23.75 million rows/s., 688.34 MB/s.)
Peak memory usage: 62.79 MiB.

让我们看看 24.4 的情况。

    ┌─origin─┬─dest─┬───────────firstseen─┬────────────lastseen─┐
 1.00WA   │ 00CL │ 2019-10-14 21:03:192019-10-14 22:42:012.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:013.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:014.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:015.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:016.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:017.00WA   │ ZGGG │ 2019-10-14 21:03:192019-10-14 22:42:018.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:019.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:0110.00WA   │ YSSY │ 2019-10-14 21:03:192019-10-14 22:42:01 │
    └────────┴──────┴─────────────────────┴─────────────────────┘

10 rows in set. Elapsed: 0.079 sec.

所以速度大约快了 8 倍。如果我们通过 SELECT * 返回所有列,则此查询在 24.3 中花费的时间将超过 4 秒,而在 24.4 中则为 0.4 秒,这相当于 10 倍的改进。

让我们看看我们能否理解它为什么更快。这两行代码值得关注。

INNER JOIN opensky AS r ON l.destination = r.origin
WHERE notEmpty(l.origin) AND notEmpty(r.destination) AND (r.origin = 'KSFO')

WHERE 子句的最后一个谓词是 r.origin = 'KSFO'。在上一行中,我们说我们只想在 l.destination = r.origin 时进行连接,这意味着 l.destination = 'KSFO' 也是如此。24.4 中的分析器知道这一点,因此可以更早地过滤掉大量行。

换句话说,我们的 WHERE 子句在 24.4 中实际上看起来像这样。

INNER JOIN opensky AS r ON l.destination = r.origin
WHERE notEmpty(l.origin) AND notEmpty(r.destination) 
AND (r.origin = 'KSFO') AND (l.destination = 'KSFO')

第二个改进是分析器现在将自动将 OUTER JOIN 转换为 INNER JOIN,如果 JOIN 后的谓词过滤掉任何未连接的行。

例如,假设我们最初编写了一个查询来查找旧金山和纽约之间的航班,包括直飞航班和转机航班。

SELECT
    l.origin,
    l.destination,
    r.destination,
    registration,
    l.callsign,
    r.callsign
FROM opensky AS l
LEFT JOIN opensky AS r ON l.destination = r.origin
WHERE notEmpty(l.destination) 
AND (l.origin = 'KSFO') 
AND (r.destination = 'KJFK') 
LIMIT 10

我们后来添加了一个额外的过滤器,仅返回 r.callsign = 'AAL1424' 的行。

SELECT
    l.origin,
    l.destination AS leftDest,
    r.destination AS rightDest,
    registration AS reg,
    l.callsign,
    r.callsign
FROM opensky AS l
LEFT JOIN opensky AS r ON l.destination = r.origin
WHERE notEmpty(l.destination) 
AND (l.origin = 'KSFO') 
AND (r.destination = 'KJFK') 
AND (r.callsign = 'AAL1424')
LIMIT 10
SETTINGS optimize_move_to_prewhere = 0

由于我们现在需要连接右侧的 callsign 列具有值,因此 LEFT JOIN 可以转换为 INNER JOIN。让我们检查一下 24.3 和 24.4 中的查询性能。

24.3

    ┌─origin─┬─leftDest─┬─rightDest─┬─reg────┬─callsign─┬─r.callsign─┐
 1. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 2. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 3. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 4. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 5. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 6. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 7. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 8. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 9. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
10. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
    └────────┴──────────┴───────────┴────────┴──────────┴────────────┘

10 rows in set. Elapsed: 1.937 sec. Processed 63.98 million rows, 2.52 GB (33.03 million rows/s., 1.30 GB/s.)
Peak memory usage: 2.84 GiB.

24.4

    ┌─origin─┬─leftDest─┬─rightDest─┬─reg────┬─callsign─┬─r.callsign─┐
 1. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 2. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 3. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 4. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 5. │ KSFO   │ 01FA     │ KJFK      │ N12221 │ UAL423   │ AAL1424    │
 6. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 7. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 8. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
 9. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
10. │ KSFO   │ 01FA     │ KJFK      │ N87527 │ UAL423   │ AAL1424    │
    └────────┴──────────┴───────────┴────────┴──────────┴────────────┘

10 rows in set. Elapsed: 0.762 sec. Processed 23.22 million rows, 939.75 MB (30.47 million rows/s., 1.23 GB/s.)
Peak memory usage: 9.00 MiB.

在 24.4 中,速度快了不到三倍。

如果您想了解更多有关如何实现 JOIN 性能改进的信息,请阅读 Maksim Kita 的博文,其中解释了所有内容。

这就是 24.4 版本的所有内容。我们希望您能加入我们 5 月 30 日的 24.5 版本电话会议。请确保您注册,以便获得 Zoom 网络研讨会的全部详细信息

分享此帖子

订阅我们的新闻稿

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