ClickHouse 23.9 版本发布说明

图片

本文字数:9889;估计阅读时间:25 分钟

审校:庄晓东(魏庄)

发布概要

新增20个新功能

实现了19项性能优化

修复了55处bug

以下是一小部分突出功能的摘要... 但是该版本包括仅在表为空时删除表、自动检测JSON格式、支持长列名、改进数字转换为日期时间、非恒定时区、备份日志改进、更多MYSQL兼容性、生成临时凭证的能力、并行读取INFILE子句的文件、支持Tableau在线等等。

新贡献者

同往常一样,我们特别欢迎所有23.9版的新贡献者!ClickHouse的受欢迎程度在很大程度上归功于社区的贡献。看到这个社区的壮大总是令人印象深刻的。

如果您在此处看到了您的姓名,请与我们联系... 不过我们也会在 Twitter 等社交媒体上找到您。

Alexander van Olst、Christian Clauss、CuiShuoGuo、Fern、George Gamezardashvili、Julia Kartseva、LaurieLY、Leonardo Maciel、Max Kainov、Petr Vasilev、Roman G、Tiakon、Tim Windelschmidt、Tomas Barton、Yinzheng-Sun、bakam412、priera、seshWCS、slvrtrn、wangtao.2077、xuzifu666、yur3k、Александр Нам。

关于JSON的类型推断

这是Pavel Kruglov贡献的。

什么时候JSON在ClickHouse中可以投入生产使用?

是的,我们经常听到这个问题。虽然我们功能开发还在继续,并且内部已经优先考虑让它在ClickHouse中投入生产状态,但我们也相信用户通常不需要使用到所有的功能。为了提供解决大多数需求的解决方案,我们很高兴介绍JSON的类型推断。

这个功能专门针对那些可预测JSON结构的用户。它允许从结构化数据中推断出嵌套模式,从而节省用户手动定义的时间。虽然这带来了一些约束,但加快了入门体验。

例如,考虑以下PyPI数据。这些数据来自BigQuery,是作为公共数据集托管的,其中包含全球各地Python软件包的每次下载(我们在早期的帖子中使用过它)。如下所示,这里的SCHEMA有多个级别:

图片

我们将这些样本数据导出到了一个GCS存储桶中。在23.9之前,ClickHouse的用户需要定义列字段才能查询这些数据。如下所示:

SELECT
  file.version,
  count() AS c
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/sample/*.json.gz', 'NOSIGN', 'JSONEachRow', 'timestamp DateTime64(9), country_code String, url String, project String, file Tuple(filename String, project String, type String, version String), details\tTuple(cpu String, distro Tuple(id String, libc Tuple(lib String, version String), name String, version String), implementation Tuple(name String, version String), installer Tuple(name String, version String), openssl_version String, python String, rustc_version String, setuptools_version String, system Tuple(name String, release String)), tls_protocol String, tls_cipher String')
WHERE project = 'requests'
GROUP BY file.version
ORDER BY c DESC
LIMIT 5

┌─file.version─┬──────c─┐
│ 2.31.0     │ 268665 │
│ 2.27.1     │  29931 │
│ 2.26.0     │  11244 │
│ 2.25.1     │  10081 │
│ 2.28.2     │   8686 │
└──────────────┴────────┘

5 rows in set. Elapsed: 21.876 sec. Processed 26.42 million rows, 295.28 MB (1.21 million rows/s., 13.50 MB/s.)
Peak memory usage: 98.80 MiB.

此外,无法从这些数据的样本中创建表并依赖于表结构推断。相反,用户需要在导入行之前手动定义表结构。

这种开销对于计划保留数据并构建生产服务的用户是可以接受的。对于新用户或那些想要进行即席分析的用户来说,它代表了使用上的障碍。从23.9开始,体验得到了简化,ClickHouse可以推断出表结构:

DESCRIBE TABLE s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/sample/*.json.gz')
FORMAT TSV

timestamp    Nullable(DateTime64(9))
country_code    Nullable(String)
url    Nullable(String)
project    Nullable(String)
file    Tuple(filename Nullable(String), project Nullable(String), type Nullable(String), version Nullable(String))
details    Tuple(cpu Nullable(String), distro Tuple(id Nullable(String), libc Tuple(lib Nullable(String), version Nullable(String)), name Nullable(String), version Nullable(String)), implementation Tuple(name Nullable(String), version Nullable(String)), installer Tuple(name Nullable(String), version Nullable(String)), openssl_version Nullable(String), python Nullable(String), rustc_version Nullable(String), setuptools_version Nullable(String), system Tuple(name Nullable(String), release Nullable(String)))
tls_protocol    Nullable(String)
tls_cipher    Nullable(String)

8 rows in set. Elapsed: 0.220 sec.

如果我们对表结构感到满意,我们可以运行以下查询来找出Python中requests库的最流行版本:

SELECT
  file.version,
  count() AS c
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/sample/*.json.gz')
WHERE project = 'requests'
GROUP BY file.version
ORDER BY c DESC
LIMIT 5

┌─file.version─┬──────c─┐
│ 2.31.0     │ 268665 │
│ 2.27.1     │  29931 │
│ 2.26.0     │  11244 │
│ 2.25.1     │  10081 │
│ 2.28.2     │   8686 │
└──────────────┴────────┘

5 rows in set. Elapsed: 4.306 sec. Processed 26.46 million rows, 295.80 MB (6.14 million rows/s., 68.69 MB/s.)
Peak memory usage: 487.79 MiB.

这也可以用来定义一个表:

CREATE TABLE pypi
ENGINE = MergeTree
ORDER BY (project, timestamp) EMPTY AS
SELECT *
FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/sample/*.json.gz') SETTINGS schema_inference_make_columns_nullable = 0

SHOW CREATE TABLE pypi FORMAT Vertical

CREATE TABLE default.pypi
(
  `timestamp` String,
  `country_code` String,
  `url` String,
  `project` String,
  `file` Tuple(filename String, project String, type String, version String),
  `details` Tuple(cpu String, distro Tuple(id String, libc Tuple(lib String, version String), name String, version String), implementation Tuple(name String, version String), installer Tuple(name String, version String), openssl_version String, python String, rustc_version String, setuptools_version String, system Tuple(name String, release String)),
  `tls_protocol` String,
  `tls_cipher` String
)
ENGINE = MergeTree
ORDER BY (project, timestamp)
SETTINGS index_granularity = 8192

请注意结构自动推断为嵌套元组。此表结构推断不会产生优化过的表结构。我们建议用户仍然手动定义表结构,以优化类型和编解码器以获得最佳性能,并仅将推断的表结构用作第一次尝试或仅用于即席分析。

那么,与JSON类型相比,这种方法有哪些局限性?

首先,要求在用于表结构推断的数据样本中指定所有列。默认情况下,ClickHouse在数据中读取前25k行或32MB(以较小者为准)来建立这些列。在此推断步骤中,结构不需要一致,行也不需要包含所有列。例如,想象一下我们有以下消息:

{"a" : 1, "obj" : {"x" : 1}}
{"b" : 2, "obj" : {"y" : 2}}

如果我们要求ClickHouse描述潜在的表结构,它将添加a和b作为潜在列。

DESCRIBE TABLE format(JSONEachRow, '{"a" : 1, "obj" : {"x" : 1}}, {"b" : 2, "obj" : {"y" : 2}}')
FORMAT TSV
a    Nullable(Int64)
obj    Tuple(x Nullable(Int64), y Nullable(Int64))
b    Nullable(Int64)

此样本后出现的新列将被忽略,即表结构不会更新。查询也不能引用样本中没有出现的列。

其次,列的类型必须一致。换句话说,不支持同一JSON路径的不同类型。例如,以下内容是无效的:

{"a" : 42}
{"a" : [1,2,3]}

我们知道一些用户拥有高度动态的数据,无法解决这些限制。因此,有了JSON类型...

GCD编解码器-更好的压缩

这是 Alexander Nam 贡献的。

在23.9中,我们添加了一个新的编解码器GCD。该编解码器基于最大公约数算法,可以显著提高对存储在列中的小数(decimal)的压缩效果,其中配置的精度远远高于所需。此编解码器还有助于处理大数(例如1201000000),并且增加幅度大,例如从1201000000到1203000000。具有类似大小和分布的整数也可以从GCD中受益,例如时间戳(例如UInt64)具有纳秒精度,以及比较"不频繁"的日志消息,例如每100毫秒一次。

该编解码器背后的思想很简单。在块级别上,我们计算列值的最大公约数,用它来除以它们。通过减少值的范围,我们增加了其他编解码器(例如Delta)的机会。甚至通用算法,如LZ4和ZSTD,也可以从这个范围的减少中受益。在查询时,使用存储的GCD值,我们可以通过简单的乘法恢复原始值。

图片

例如,考虑上图中的第一行。初始值为1,201,000,000,存储为1,201,GCD为1,000,000。在查询时,值1,201将乘以1,000,000以恢复到1,201,000,000。

减小值的范围还有另一个好处,即增加了其他编解码器(例如Delta)进一步压缩数据的机会。甚至通用算法,如LZ4和ZSTD,也可以从这种范围的减少中受益。

例如,为了展示GCD编解码器的潜在好处,我们在下面使用了一个超过110亿行的外汇数据集。该数据集包含两个小数列,bid 和 ask,我们评估了GCD编解码器对以下4个表配置的压缩的影响:

  • forex_v1-Decimal(76,38)CODEC(ZSTD)-这里的精度和比例远远大于所需值,导致 bid 和 ask 以比所需更大的整数表示存储。应用了ZSTD压缩。

  • forex_v2-Decimal(76,38)CODEC(GCD,ZSTD)-与上述相同,但在ZSTD压缩之前应用了GCD编解码器。

  • forex_v3-Decimal(11,5)CODEC(ZSTD)-值的最佳(最小)精度和比例。应用了ZSTD压缩。

  • forex_v4-Decimal(11,5)CODEC(GCD,ZSTD)-具有GCD编解码器和ZSTD的最佳精度和比例。

*在所有情况下都是ZSTD(1)。

注意:内部小数以普通有符号整数存储,精度确定所需的位数。

下面是示例表结构和数据加载:

CREATE TABLE forex
(
  `datetime` DateTime64(3),
  `bid` Decimal(11, 5) CODEC(ZSTD(1)),
  `ask` Decimal(11, 5) CODEC(ZSTD(1)),
  `base` LowCardinality(String),
  `quote` LowCardinality(String)
)
ENGINE = MergeTree
ORDER BY (base, quote, datetime)

INSERT INTO forex
SELECT *
FROM s3Cluster('default', 'https://datasets-documentation.s3.eu-west-3.amazonaws.com/forex/csv/year_month/*.csv.zst', 'CSVWithNames')
SETTINGS min_insert_block_size_rows = 10000000, min_insert_block_size_bytes = 0, parts_to_throw_insert = 50000, max_insert_threads = 30, parallel_distributed_insert_select = 2

我们可以使用以下查询检查每个表配置的 bid 和 ask 列的压缩情况:

SELECT
  table,
  name,
  any(compression_codec) AS codec,
  any(type) AS type,
  formatReadableSize(sum(data_compressed_bytes)) AS compressed_size,
  formatReadableSize(sum(data_uncompressed_bytes)) AS uncompressed_size,
  round(sum(data_uncompressed_bytes) / sum(data_compressed_bytes), 2) AS ratio
FROM system.columns
WHERE (table LIKE 'forex%') AND (name IN ['bid', 'ask'])
GROUP BY
  table,
  name
ORDER BY
  table ASC,
  name DESC

┌─table────┬─name─┬─codec───────────────┬─type───────────┬─compressed_size─┬─uncompressed_size─┬─ratio─┐
│ forex_v1 │ bid  │ CODEC(ZSTD(1))    │ DECIMAL(76, 38)│ 23.56 GiB        │ 345.16 GiB         │ 14.65 │
│ forex_v1 │ ask  │ CODEC(ZSTD(1))    │ DECIMAL(76, 38)│ 23.61 GiB        │ 345.16 GiB         │ 14.62 │
│ forex_v2 │ bid  │ CODEC(GCD, ZSTD(1)) │ DECIMAL(76, 38)│ 14.47 GiB        │ 345.16 GiB         │ 23.86 │
│ forex_v2 │ ask  │ CODEC(GCD, ZSTD(1)) │ DECIMAL(76, 38)│ 14.47 GiB        │ 345.16 GiB         │ 23.85 │
│ forex_v3 │ bid  │ CODEC(ZSTD(1))    │ DECIMAL(11, 5) │ 11.99 GiB        │ 86.29 GiB          │   7.2 │
│ forex_v3 │ ask  │ CODEC(ZSTD(1))    │ DECIMAL(11, 5) │ 12.00 GiB        │ 86.29 GiB          │  7.19 │
│ forex_v4 │ bid  │ CODEC(GCD, ZSTD(1)) │ DECIMAL(11, 5) │ 9.77 GiB         │ 86.29 GiB          │  8.83 │
│ forex_v4 │ ask  │ CODEC(GCD, ZSTD(1)) │ DECIMAL(11, 5) │ 9.78 GiB         │ 86.29 GiB          │  8.83 │
└──────────┴──────┴─────────────────────┴────────────────┴─────────────────┴───────────────────┴───────┘

如上所示,用不必要的高精度和比例定义列对压缩和未压缩大小有重大影响,其中 forex_v1 占用的空间几乎是其他配置的两倍,为 23.56 GiB。虽然GCD不会影响未压缩大小,但它将压缩大小减少了38%,至 14.47GiB 。因此,在使用高于所需精度时,GCD非常有用。

这些结果还显示,指定正确的精度和比例可以提供显著的改进,forex_v3 仅消耗 12 Gib。未压缩大小的减小仅为大小的 1/4 ,由于每个值使用的位数较低,因此更可预测,为'64 vs 256'。

最后,即使使用了优化的精度和比例,GCD编解码器在这里也提供了显着的压缩改进。我们将列的压缩大小减少了近20%,至9.8GiB。

这些结果展示了GCD编解码器的潜力。如果您发现它有用并节省了空间,请告诉我们!

简单的SSH密钥身份验证

这是 George Gamezardashvili 贡献的。

数据工程师和数据库管理员每次使用不同密码登录许多ClickHouse集群时,希望能能实现此功能。ClickHouse现在支持通过SSH密钥进行身份验证的功能。用户只需将其公钥添加到ClickHouse配置文件中即可。

$ cat users.d/alexey.yaml

users:
  alexey:
  ssh_keys:
    ssh_key:
      type: ssh-rsa
      # cat ~/.ssh/id_rsa.pub
      base64_key: 'AAAAB3NzaC1yc2EAAAABIwAAAQEAoZiwf7tVzIXGW26cuqnu...'

或通过DDL

CREATE USER alexey IDENTIFIED WITH ssh_key BY KEY 'AAAAB3NzaC1yc2EAAAABIwAAAQEAoZiwf7tVzIXGW26cuqnu...' TYPE 'ssh-rsa'

连接到ClickHouse服务器时,用户不需要提供密码,而是指定私钥的路径。

$ clickhouse-client --ssh-key-file ~/.ssh/id_rsa --user alexey

每次都需要提供SSH密钥路径可能会让某些用户感到沮丧,尤其是如果要连接多个服务器。请不要忘记您也可以通过配置文件配置客户端设置。此文件位于您的主目录中,即 ~/.clickhouse-client/config.xml。可以如下配置上述设置:

<?xml version="1.0" ?>
<config>
    <secure>1</secure>
    <host>default_host</host>
    <openSSL>
      <client>
        <loadDefaultCAFile>true</loadDefaultCAFile>
        <cacheSessions>true</cacheSessions>
        <disableProtocols>sslv2,sslv3</disableProtocols>
        <preferServerCiphers>true</preferServerCiphers>
        <invalidCertificateHandler>
          <name>RejectCertificateHandler</name>
        </invalidCertificateHandler>
      </client>
    </openSSL>
    <prompt_by_server_display_name>
      <default>{display_name} :) </default>
    </prompt_by_server_display_name>
  <!--Specify private SSH key-->
  <user>alexey</user>
  <ssh-key-file>~/.ssh/id_rsa</ssh-key-file>
</config>

只要您的公钥已经分发到我们的ClickHouse实例配置中,您就可以在不指定公钥位置的情况下连接。

clickhouse-client --host <optional_host_if_not_default>

注意:使用SSH密钥时,用户将被提示输入密码。可以通过参数 --ssh-key-passphrase 配置,或者直接在响应中配置。

工作负载调度-强大功能的基础

这是 Sergei Trifonov 贡献的。

ClickHouse最受期待的功能之一是能够隔离查询工作负载。具体而言,用户经常需要为一组查询定义资源限制,以最小化其影响。这里的目标通常是确保这些查询不会影响其他关键业务查询。

例如,ClickHouse管理员可能需要运行一个预计会消耗大量资源并需要几分钟甚至几小时才能完成的大型查询。在执行此查询的同时,ClickHouse必须继续为关键业务应用程序提供快速查询。理想情况下,长时间运行的查询应以不影响更小的关键快速查询的方式执行。

尽管在ClickHouse中部分实现了内存配额和CPU限制,但我们承认目前不那样容易实现。并且还没有办法限制共享资源(如磁盘I/O)的使用。

因此,我们很高兴宣布工作负载调度的基础。

尽管该功能的初始实现重点是能够调度远程磁盘IO,但它包括了其他资源可以添加到的框架和基础。

创建工作负载后,可以通过设置工作负载来调度查询,例如:

SELECT count() FROM my_table WHERE value = 42 SETTINGS workload = 'long_running_limited'
SELECT count() FROM my_table WHERE value = 42 SETTINGS workload = 'priority'

有关如何配置工作负载计划的详细信息,请参阅文档(地址:https://clickhouse.com/docs/en/operations/workload-scheduling)。

图片

联系我们

手机号:13910395701

邮箱:[email protected]

满足您所有的在线分析列式数据库管理需求

猜你喜欢

转载自blog.csdn.net/ClickHouseDB/article/details/134273543