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

博客 / 工程

ClickHouse 22.12 版本发布

author avatar
ClickHouse 团队
2022年12月19日

节日盛宴。

团队发布了 11 个月的常规版本,但这还不够。ClickHouse Cloud 的抢先体验版、Beta 版和 GA 版也已发布。说到这里,如果您想要在生产环境(或开发环境)中运行 ClickHouse 的最简单方法,请立即开始免费试用 ClickHouse Cloud

作为节日礼物,我们很高兴推出 22.12 版本。

版本摘要

17 个新功能。8 项性能优化。39 个错误修复。

如果这些还不足以引起您的兴趣,请查看一些重点内容

  • grace_hash JOIN
  • 密码复杂度规则
  • BSON 支持
  • GROUP BY ALL 支持
  • 为 ClickHouse Keeper 添加 Prometheus 端点

当然,还有许多性能改进。

GraceHopper哈希连接 (Sergei Skvortsov + Vladimir Cherkasov)

在 ClickHouse 的历史中,用户在连接方面有几个选择:可以使用 hash 方法,该方法速度很快但受内存限制,或者恢复使用 partial_merge 算法。后者依赖于对数据进行排序并将其转储到磁盘,通常以牺牲性能为代价来克服内存限制。虽然这至少允许用户执行大型连接,但它通常性能较慢。在此版本中,我们为连接算法引入了一个令人兴奋的非内存绑定补充,它克服了部分合并的一些性能挑战:Grace Hash。

Grace Hash 算法 使用两阶段方法来连接数据。我们的实现与 经典算法描述 略有不同,以便适应我们的查询管道。

我们的第一阶段读取右侧表并根据键列的哈希值将其拆分为 N 个桶(最初,N 为 grace_hash_join_initial_buckets)。这样做是为了确保可以独立处理每个桶。来自第一个桶的行被添加到内存中的哈希表中,而其他行则保存到磁盘。如果哈希表的大小超过内存限制(例如,由 max_bytes_in_join 设置),我们会增加桶的数量并重新计算每行的分配桶。任何不属于当前桶的行都会被刷新并重新分配。

right-side-grace.png

然后读取左侧表。与第一个桶对应的行被连接(因为哈希表在内存中),其他行被刷新到其相应的基于磁盘的桶中。这两个步骤的关键在于,哈希函数将始终将值分配到相同的桶,从而有效地对数据进行分区,并通过分解来解决问题。

left-side-grace.png

完成读取左侧表后,我们必须处理磁盘上剩余的桶。这些桶按顺序处理。我们从右侧表数据为每个桶构建哈希表。同样,如果内存不足,我们必须增加桶的数量。从右侧桶构建哈希表后,我们流式传输左侧桶并完成这对桶的连接。请注意,在此步骤中,我们可能会得到一些不属于当前桶的行,因为它们是在增加桶的数量之前保存的。在这种情况下,我们将它们保存到新的实际桶中并进一步处理它们。此过程对所有剩余的桶重复。

grace-final-step.png

这种数据分区方法确保我们既可以限制内存,也可以限制需要扫描每个表的时间。表的双方都被扫描了两次——一次用于对数据进行分区,另一次用于连接阶段。虽然不像哈希连接那样快,但与 partial_merge 相比,性能优势可能很明显。

现在让我们来看一个实际的例子。

在我们的 play.clickhouse.com 中,我们在 hits 表中维护了一个匿名化的 网络分析数据集。此表中的每一行都表示一个网站点击,记录浏览器代理和 URL 等详细信息。数据集还包含一个 Referer 列(也是一个 URL),指示访问者到达每个 URL 之前的上一个位置。假设我们确定访问 URL 之前的两个页面,而不仅仅是直接的引用。我们可以通过时间排序来解决这个问题,但让我们故意使它更复杂,并通过图分析来解决。这需要我们有效地进行深度为 2 的图导航,如下所示

url-self-join.png

这可以在 SQL 中实现为自连接,其中我们将 hits 表与自身连接,以查找共享公共 URL 和 Referer 值的行对。

SELECT UserID, h1.Referer, h1.URL, h2.URL FROM hits AS h1 INNER JOIN hits AS h2 ON h1.UserID = h2.UserID AND h1.URL = h2.Referer WHERE h1.URL != '' AND h2.URL != '' AND h1.Referer != '' AND h2.Referer != '' ORDER BY UserID ASC LIMIT 10

虽然此查询的结果并不特别有趣,但我们注意到下面 hashparallel_hashpartial_mergegrace_join 算法的性能和内存开销。

hash-algorithms.png hash-join-results.png

注意:parallel_hashhash 连接的一个变体,它将数据拆分为多个桶并同时构建多个哈希表,而不是一个,以加快连接速度,但会增加内存开销。

这里的结果非常清楚。Grace 在性能方面优于 partial_merge,但会增加更多的内存开销。虽然 hash,尤其是 parallel_hash,速度快得多,但您需要支付开销并依赖于有足够的内存。这里的选择取决于用户。请注意,这些结果会因您的数据和查询而异。

请注意,此处的 Grace Hash 测试是在 grace_hash_join_initial_buckets=128 设置下运行的。选择 grace_hash_join_initial_buckets 的“正确”值的的主要好处是避免了我们之前描述的重新分桶——这可能会加快 JOIN 的速度。目前,这需要用户手动调整。

强制执行密码复杂度规则 (Nikolay Degterinsky)

ClickHouse 将安全性视为一等公民。在 22.12 之前,用户可以创建密码而无需强制执行复杂性。虽然我们相信我们的用户会负责任,但错误和疏忽总会发生,并且可能会创建弱密码。我们需要出于 ClickHouse Cloud 的自身需求关闭此功能,但这也是我们的社区需要的。

可以通过在服务器配置中添加 password_complexity 配置键来设置密码强制执行。以下是强制执行强标准的 4 条规则示例

$ cat /etc/clickhouse-server/config.d/rules.yaml password_complexity: - rule: pattern: '.{12}' message: 'be at least 12 characters long' - rule: pattern: '\p{N}' message: contain at least 1 numeric character - rule: pattern: '\p{Lu}' message: contain at least 1 uppercase character - rule: pattern: '[^\p{L}\p{N}]' message: contain at least 1 special character

现在,尝试违反此策略会导致错误,例如:

clickhouse-cloud:) CREATE USER vasyan IDENTIFIED WITH sha256_password BY 'qwerty123' DB::Exception: Invalid password. The password should: be at least 12 characters long, contain at least 1 uppercase character, contain at least 1 special character.

我们始终建议用户使用 clickhouse-client 创建用户并设置密码。除了确认密码满足客户端规则外,它还确保明文密码永远不会传输到服务器。

BSON 支持(Pavel Kruglov、Mark Polokhov)

BSON(Binary Javascript Object Notation)是一种二进制编码的 Javascript Object Notation (JSON) 格式,用于在 MongoDB 中存储数据和网络传输。虽然基于 JSON,但它具有一些优势:具体来说,它支持其他类型,例如日期和二进制数据,并且由于长度和数组索引被编码到格式中,因此构建和扫描速度更快。我们预计大多数用户在与 mongodump 工具创建的转储交互时会发现此功能很有用。

Mongo 示例数据集 提供了一些有用的示例来测试此功能。假设您已将这些数据集加载到您的 Mongo 或 Atlas 实例中,那么使用 ClickHouse 导出和查询将变得非常简单。下面我们使用 clickhouse-local 并查询 电影数据集中的评论

mongodump --uri="/sample_mflix" --username=default --db=sample_mflix --collection=comments --out=comments clickhouse-local SELECT count() FROM file('comments/sample_mflix/comments.bson', BSONEachRow) ┌─count()─┐ │ 41079 │ └─────────┘ 1 row in set. Elapsed: 0.236 sec. Processed 36.86 thousand rows, 21.18 MB (156.37 thousand rows/s., 89.84 MB/s.) SELECT name, text FROM file('comments/sample_mflix/comments.bson', BSONEachRow) LIMIT 1 FORMAT Vertical Query id: 7d522673-f124-4598-bdff-86b12f2905d1 Row 1: ────── name: Mercedes Tyler text: Eius veritatis vero facilis quaerat fuga temporibus. Praesentium expedita sequi repellat id. Corporis minima enim ex. Provident fugit nisi dignissimos nulla nam ipsum aliquam. 1 row in set. Elapsed: 0.048 sec.

ClickHouse Keeper - Prometheus 端点(Antonio Andelic)

我们一直认为 ClickHouse Keeper 已准备好投入生产,并鼓励所有用户尽可能从 Zookeeper 迁移。但是,对于某些用户而言,使用与旧版 Zookeeper 实例相同的方法在其部署中监控 ClickHouse Keeper 的能力是迁移的障碍。除了在此版本中提高高请求率下的写入性能外,我们还在 ClickHouse Keeper 中添加了一个 Prometheus 端点,以允许监控 ClickHouse 集群中这一关键软件。希望这能解除一些迁移障碍,让更多用户能够在负载下受益于更稳定的集群协调。

$ cat /etc/clickhouse-keeper/config.d/prometheus.yaml prometheus: port: 9369 endpoint: /metrics

GROUP BY ALL(TaoFengLiu)

来自 OLTP 数据库(如 Postgres)的新 ClickHouse 用户很快就会发现 ClickHouse 在某些方面与 ANSI SQL 不同。这通常是故意的,因为我们认为这些差异使分析查询更简单、更简洁易写。但是,在少数情况下,我们确实存在一些功能差距,我们渴望弥补。其中之一是在 GROUP BY 中使用 ALL 子句的能力。此简单功能意味着用户无需重复 SELECT 子句中的列(这些列不是聚合函数),从而使查询更短、更易编写。由于我们热爱速度,因此您现在可以在 22.12 中使用此功能 感谢社区的贡献

SELECT county, town, district, street, median(price) AS med_price, count() AS c FROM uk_price_paid WHERE toYear(date) = 2022 GROUP BY county, town, district, street ORDER BY count() DESC LIMIT 10 // and even simpler with ALL SELECT county, town, district, street, median(price) AS med_price, count() AS c FROM uk_price_paid WHERE toYear(date) = 2022 GROUP BY ALL ORDER BY count() DESC LIMIT 10

分享此帖子

订阅我们的新闻通讯

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