博客 / 工程

ClickHouse 与 Snowflake 在实时分析方面的比较和迁移

author avatar
ClickHouse 团队
2023 年 9 月 6 日 - 28 分钟阅读

clickhouse_vs_snowflake_simple.png

摘要

本 ClickHouse 与 Snowflake 博客系列包含两部分,可以独立阅读。这两部分如下:

  • 比较和迁移 - 这篇文章重点概述了 ClickHouse 和 Snowflake 之间的架构异同,并回顾了 ClickHouse Cloud 中特别适合实时分析用例的功能。对于有兴趣将工作负载从 Snowflake 迁移到 ClickHouse 的用户,我们探讨了数据集的差异以及迁移数据的方法。

  • 基准测试和成本分析 - 本系列中的另一篇文章针对一组将为拟议应用程序提供支持的实时分析查询进行了基准测试。这些查询在两个系统中都进行了评估,使用了广泛的优化,并直接比较了成本。我们的结果表明,对于我们的基准测试,ClickHouse Cloud 在成本和性能方面均优于 Snowflake

    • 在生产环境中,ClickHouse Cloud 的成本效益比 Snowflake 高 3-5 倍。
    • ClickHouse Cloud 的查询速度比 Snowflake 快 2 倍以上。
    • ClickHouse Cloud 的数据压缩率比 Snowflake 高 38%。

简介

Snowflake 是一个云数据仓库,主要专注于将传统的本地数据仓库工作负载迁移到云端。它经过良好优化,可以大规模执行长时间运行的报告。随着数据集迁移到云端,数据所有者开始思考如何从这些数据中提取更多价值,包括使用这些数据集为内部和外部用例提供实时应用程序支持。当这种情况发生时,他们意识到他们需要一个针对实时分析进行优化的数据库,例如 ClickHouse。

在整个评估过程中,我们力求公平,并承认 Snowflake 提供的一些出色功能,尤其是在数据仓库用例方面。虽然我们认为自己是 ClickHouse 专家,但我们不是 Snowflake 专家,我们欢迎经验更丰富的 Snowflake 用户提供贡献和改进。我们承认 Snowflake 也可用于许多其他用例,但这超出了本文的范围。

ClickHouse 与 Snowflake

相似之处

Snowflake 是一个基于云的数据仓库平台,为存储、处理和分析大量数据提供了可扩展且高效的解决方案。与 ClickHouse 类似,Snowflake 不是建立在现有技术之上,而是依赖于自己的 SQL 查询引擎和自定义架构。

Snowflake 的架构被描述为 共享磁盘(我们更喜欢使用“共享存储”一词)和 无共享 架构的混合体。在共享磁盘架构中,数据可以从所有计算节点(共享磁盘)使用对象存储(如 S3)进行访问;而在无共享架构中,每个计算节点在本地存储整个数据集的一部分以响应查询。理论上,这 兼具两种模型的优点:共享磁盘架构的简单性和无共享架构的可扩展性。

这种设计从根本上依赖于对象存储作为主要存储介质,对象存储几乎可以在并发访问下无限扩展,同时提供高弹性和可扩展的吞吐量保证。

snowflake_architecture.png 来源:https://docs.snowflake.com/en/user-guide/intro-key-concepts

相反,作为开源和云托管产品,ClickHouse 可以部署在共享磁盘和无共享架构中。后者是自管理部署的典型架构。虽然共享磁盘架构允许轻松扩展 CPU 和内存,但无共享配置引入了经典的数据管理挑战和数据复制的开销,尤其是在成员变更期间。

因此,ClickHouse Cloud 使用了概念上类似于 Snowflake 的共享存储架构。数据在对象存储(单副本)中存储一次,例如 S3 或 GCS,从而提供几乎无限的存储和强大的冗余保证。每个节点都可以访问此单一数据副本以及用于缓存目的的本地 SSD。反过来,可以扩展节点以根据需要提供额外的 CPU 和内存资源。与 Snowflake 类似,S3 的可扩展性属性解决了共享磁盘架构的经典限制(磁盘 I/O 和网络瓶颈),确保集群中当前节点可用的 I/O 吞吐量不会因添加其他节点而受到影响。

clickhouse_architecture.png

不同之处

除了底层存储格式和查询引擎外,这些架构在一些细微之处有所不同

  • Snowflake 中的计算资源通过 仓库 的概念提供。这些仓库由多个节点组成,每个节点的大小都已设定。虽然 Snowflake 没有公布其仓库的具体架构,但 普遍认为 每个节点由 8 个 vCPU、16GiB 内存和 200GB 本地存储(用于缓存)组成。节点的数量取决于 T 恤尺码,例如,超小号有一个节点,小号 2 个,中号 4 个,大号 8 个等等。这些仓库独立于数据,可用于查询驻留在对象存储上的任何数据库。当仓库空闲且未承受查询负载时,仓库会暂停 - 并在收到查询时恢复。存储成本始终反映在账单中,但仓库仅在活动时收费。
  • ClickHouse Cloud 采用了类似的带有本地缓存存储的节点原则。用户无需选择 T 恤尺码,而是部署具有总计算量和可用 RAM 的服务。然后,这将根据查询负载透明地自动扩展(在定义的限制内) - 通过垂直扩展(增加或减少每个节点的资源)或水平扩展(增加/减少节点总数)。与 Snowflake 的 1:2 不同,ClickHouse Cloud 节点目前的 CPU 与内存比率为 1:4。虽然可能实现更宽松的耦合,但服务目前与数据耦合,这与 Snowflake 仓库不同。节点在空闲时也会暂停,并在受到查询时恢复。用户也可以根据需要手动调整服务大小。
  • 与 Snowflake 的查询缓存不同(Snowflake 的查询缓存在独立于仓库的服务层交付),ClickHouse Cloud 的查询缓存目前是节点特定的。尽管如此,基于我们的基准测试,上述节点缓存的性能优于 Snowflake。
  • Snowflake 和 ClickHouse Cloud 采用不同的方法来扩展以提高查询并发性。Snowflake 通过称为 多集群仓库 的功能来解决此问题。此功能允许用户向仓库添加集群。虽然这不能提高查询延迟,但它确实提供了额外的并行化并允许更高的查询并发性。ClickHouse 通过垂直或水平扩展向服务添加更多内存和 CPU 来实现此目的。在本文中,我们不探讨这些服务扩展到更高并发性的能力,而是侧重于延迟,但承认应该为此进行完整比较。但是,我们预计 ClickHouse 在任何并发性测试中都会表现良好,而 Snowflake 明确限制了 仓库允许的最大并发查询数为 8(默认值)。相比之下,ClickHouse Cloud 允许每个节点执行多达 1000 个查询。
  • Snowflake 能够在数据集上切换计算大小,再加上仓库的快速恢复时间,使其成为即席查询的出色体验。对于数据仓库和数据湖用例,这提供了优于其他系统的优势。

我们在下面提供了有关功能和数据类型的其他异同列表。

实时分析

根据我们的基准分析,ClickHouse 在以下方面优于 Snowflake,适用于实时分析应用程序

  • 查询延迟:即使对表应用了集群以优化性能,Snowflake 查询的查询延迟也更高。在我们的测试中,当应用过滤器(该过滤器是 Snowflake 集群键或 ClickHouse 主键的一部分)时,Snowflake 需要超过两倍的计算资源才能达到与 ClickHouse 相当的性能。虽然 Snowflake 的 持久查询缓存 缓解了一些延迟挑战,但在过滤器条件更加多样化的情况下,这无效。此查询缓存的有效性可能会因基础数据的更改而进一步受到影响,当表更改时,缓存条目会失效。虽然在我们的应用程序的基准测试中并非如此,但实际部署将需要插入新的、更近的数据。请注意,ClickHouse 的查询缓存是节点特定的,而不是 事务一致的,使其 更适合 实时分析。用户还可以精细控制其使用,能够控制其在 每个查询的基础上 的使用、其 精确大小、是否 缓存查询(持续时间或所需执行次数的限制)以及是否仅 被动使用
  • 更低的成本:可以将 Snowflake 仓库配置为在查询不活动一段时间后暂停。暂停后,不会产生费用。实际上,此不活动检查 只能降低到 60 秒。一旦收到查询,仓库将在几秒钟内自动恢复。由于 Snowflake 仅在仓库使用时收取资源费用,因此这种行为适合经常处于空闲状态的工作负载,例如即席查询。

    但是,许多实时分析工作负载需要持续的实时数据摄取和频繁的查询,而这并不能从空闲中受益(例如面向客户的仪表板)。这意味着仓库通常必须完全处于活动状态并产生费用。这抵消了空闲的成本优势以及可能与 Snowflake 能够比其他替代方案更快地恢复响应状态相关的任何性能优势。当这种活动状态要求与 ClickHouse Cloud 更低的每秒活动状态成本相结合时,ClickHouse Cloud 将为这类工作负载提供显着更低的总成本。
  • 功能的可预测定价: 诸如物化视图和集群(相当于 ClickHouse 的 ORDER BY)等功能是实时分析用例中达到最高性能水平所必需的。这些功能在 Snowflake 中会产生额外费用,不仅需要更高的层级(这会将每个积分的成本提高 1.5 倍),而且还会产生不可预测的后台成本。例如,物化视图会产生后台维护成本,集群也是如此,这在使用前很难预测。相比之下,这些功能在 ClickHouse Cloud 中不会产生额外成本,除了插入时额外的 CPU 和内存使用量,这通常可以忽略不计,除非是高插入工作负载用例。我们在基准测试中观察到,这些差异以及更低的查询延迟和更高的压缩率,导致 ClickHouse 的成本显着降低。

ClickHouse 用户还对 ClickHouse 提供的广泛的实时分析功能支持表示赞赏,例如

  • 广泛的专用分析函数缩短并简化了查询语法,例如 聚合组合器数组函数,从而提高了复杂查询的性能和可读性。
  • SQL 查询语法旨在使分析查询更轻松,例如,ClickHouse 不像 Snowflake 那样在 SELECT 中强制执行别名。
  • 更具体的数据类型,例如支持枚举和具有显式精度的数值类型。后者允许用户节省未压缩的内存。Snowflake 将较低精度的数值类型视为等效全精度类型的别名。
  • Snowflake 中更有限的选择 相比,更出色的 文件和数据格式 支持,简化了分析数据的导入和导出。
  • 联邦查询功能,支持针对各种数据湖和数据存储(包括 S3、MySQL、PostgreSQL、MongoDB、Delta Lake 等)进行即席查询。
  • 指定列的 自定义架构或编解码器 以实现更高压缩率的能力。此功能使我们能够在基准测试中优化压缩率。
  • 二级索引和投影。ClickHouse 支持 二级索引,包括用于文本匹配的 倒排索引,以及 投影,允许用户针对特定查询进行优化。虽然投影在概念上类似于 Snowflake 物化视图,但它们不受 相同限制 的约束,并且支持所有聚合函数。投影的使用也不会影响定价(这会导致 Snowflake 中的层级更改,使费用乘以 1.5 倍),除了增加存储的关联开销。我们在基准分析中证明了这些功能的有效性。
  • 支持物化视图。这些视图与 Snowflake 物化视图(后者更类似于 ClickHouse 投影)不同,因为它们是仅在插入数据时执行的触发器。ClickHouse 物化视图 比投影具有明显的优势,特别是
    • 物化视图的结果可以存储在另一个表中。这可以是插入数据的子集或聚合,并且可以显着更小。与投影(或 Snowflake 中的物化视图)不同,原始插入的数据不需要保留,从而可能大幅节省存储空间。如果用户只需要存储汇总数据,则物化视图可以提供显着的存储和性能提升。
    • 支持连接和 WHERE 过滤器,这与投影不同。
    • 物化视图可以链接,即,当插入数据时,可以执行多个视图,每个视图都生成自己的汇总数据形式。

集群与排序

ClickHouse 和 Snowflake 都是面向列的数据库。对于分析工作负载,这种数据方向优于按行存储和执行,因为它能更有效地利用 CPU 缓存和 SIMD 指令。此外,它确保可以更有效地压缩排序后的列,因为常见的压缩算法可以利用重复值。虽然它们的数据存储方法不同,但这两个系统都需要排序和索引才能获得最佳读取性能。这创建了一些类似的概念,用户可以在对比系统之间的数据并进行迁移时利用这些概念,即使实现方式有所不同。

ClickHouse 的核心是使用稀疏索引和排序数据。在创建表时,用户指定一个包含列元组的 ORDER BY 子句。这显式控制数据的排序方式。通常,应根据频繁查询选择这些 列,并按基数递增的顺序排列。 除了控制磁盘上数据的顺序外,默认情况下,ORDER BY 还会配置关联的稀疏主索引。这可以被 PRIMARY KEY 子句覆盖。请注意,ORDER BY 必须包含 PRIMARY KEY 作为前缀,因为后者假定数据已排序(有关这些可能不同的示例,请参阅 此处)。此稀疏索引依赖于磁盘上排序的数据,并且对于 ClickHouse 中的快速查询执行至关重要,因为它允许有效地扫描数据,并在数据与谓词不匹配时跳过数据。

Snowflake 在磁盘上的 存储结构 与微分区有所不同,但通过 集群 提供了类似的概念。此子句允许用户指定一组列,这些列控制如何将数据分配给微分区,旨在确保具有相同列值的数据位于同一位置。通过有效地控制磁盘上的数据顺序,与 ClickHouse 的 ORDER BY 相比,集群在性能和压缩方面提供了类似的增益。

尽管它们在概念上相似,但它们的实现方式存在一些差异,这些差异会影响后续使用

  • ClickHouse 在插入时根据 ORDER BY 对数据进行排序,并在将数据写入磁盘时构建稀疏索引。写入时没有额外成本和可忽略不计的开销,即使对于快速更改的表,也可以进行适当的优化。
  • Snowflake 异步执行集群,在后台消耗积分,以在称为 自动集群 的过程中保持数据分配到正确的分区。在此过程中将消耗的积分无法轻易预测。虽然 Snowflake 不建议对快速更改的表进行集群,但对于经常查询且数据量达数 TB 的表,集群是合适的。所用列的基数将严重影响集群的开销和消耗的积分 - Snowflake 建议使用表达式(例如 to_date)来减轻这种影响。对于用户而言最重要的是,集群何时发生是不确定的,因此其优势不会在应用于表时立即显现。该过程是增量的,集群会随着时间的推移而改进,然后在稳定下来(假设不再添加数据)。
  • Snowflake 允许以 潜在的高成本 重新集群数据。由于微分区方法,这在 Snowflake 中是可能的,而在 ClickHouse 中,则需要完全重写数据。

无论上述差异如何,这些功能对于分析工作负载至关重要,分析工作负载需要选择、过滤和排序特定列,并使用 GROUP BY 操作来支持构建具有向下钻取的图表。在这两种情况下,将各自子句中使用的列映射到工作负载都很重要。很大一部分查询应受益于集群/排序键,并且大多数查询都应命中这些列。

在为 ORDER BYCLUSTER BY 子句选择列时,ClickHouse 和 Snowflake 提供了类似的建议

  • 使用在选择性过滤器中积极使用的列。GROUP BY 操作中使用的列也有助于提高内存利用率。
  • 尝试使用具有足够基数的列,以确保有效地修剪表,例如,包含抛硬币结果的列通常会修剪 < 50% 的表。
  • 在定义多个列时,用户应尝试确保列按从最低到最高基数排序。通常,在两种情况下,这将使以后列的过滤更有效。虽然 Snowflake 的详细信息不可用,但我们预计这与 这对于 ClickHouse 很重要的原因 类似。

注意:虽然上述建议一致,但 Snowflake 建议避免在集群键中使用高基数列。但这不会影响 ClickHouse,但是,诸如 timestamp 之类的列是 ORDER BY 子句的有效选择。

我们在后续基准测试中考虑了这些建议。

迁移数据

希望在 Snowflake 和 ClickHouse 之间迁移数据的用户可以使用对象存储(例如 S3)作为传输的中间存储。此过程依赖于分别使用 Snowflake 和 ClickHouse 的 COPY INTOINSERT INTO SELECT 命令。我们在下面概述此过程。

migrating_clickhouse_snowflake.png

从 Snowflake 卸载

Snowflake 导出需要使用 外部 Stage,如上图所示。这在概念上类似于 ClickHouse S3 表引擎,通过逻辑上封装一组外部托管文件并允许在 SQL 语句中一致地引用它们。

我们建议使用 Parquet 作为系统之间传输数据的中间格式,主要是因为它允许共享类型信息,保留精度,压缩良好,并原生支持分析中常见的嵌套结构。用户还可以卸载到 ndjson 格式的 JSON - ClickHouse 通过 JSONEachRow 支持此格式,但这通常明显更冗长,并且解压缩后更大。

在下面的示例中,我们卸载了 650 亿行的 PyPi 数据集。此架构和数据集源自 公共 BigQuery 表,在 我们的基准测试 中进行了更详细的描述。此数据集 包含使用 PiP 等工具下载的每个 Python 包的行。选择此数据集是因为它的大小(所有数据超过 5500 亿行)以及具有类似于实时分析用例中遇到的架构和结构。

在下面的示例中,我们在 Snowflake 中创建了一个 命名文件格式 来表示 Parquet 和所需的文件选项。然后,在声明外部 Stage 时使用它,COPY INTO 命令将与该外部 Stage 一起使用。这为 S3 存储桶提供了抽象,可以通过该抽象授予权限。

请注意,Snowflake 提供了几种方法 来共享对 S3 存储桶的写入访问权限的凭据。虽然我们使用了选项 3,即在声明 Stage 时直接使用密钥和密钥来简化以下示例,但在生产中建议使用 Snowflake 存储集成 方法,以避免共享凭据。

CREATE FILE FORMAT my_parquet_format TYPE = parquet;

CREATE OR REPLACE STAGE my_ext_unload_stage 
URL='s3://datasets-documentation/pypi/sample/'
CREDENTIALS=(AWS_KEY_ID='<key>' AWS_SECRET_KEY='<secret>')
FILE_FORMAT = my_parquet_format;

-- apply pypi prefix to all files and specify a max size of 150mb
COPY INTO @my_ext_unload_stage/pypi from pypi max_file_size=157286400 header=true;

Snowflake 架构

CREATE TABLE PYPI (
   timestamp TIMESTAMP,
   country_code varchar,
   url varchar,
   project varchar,
   file OBJECT,
   installer OBJECT,
   python varchar,
   implementation OBJECT,
   distro VARIANT,
   system OBJECT,
   cpu varchar,
   openssl_version varchar,
   setuptools_version varchar,
   rustc_version varchar,
   tls_protocol varchar,
   tls_cipher varchar
) DATA_RETENTION_TIME_IN_DAYS = 0;

导出到 Parquet 时,它生成了 5.5TiB 的数据,最大文件大小为 150MiB。位于同一 AWS us-east-1 区域的 2X-LARGE 仓库大约需要 30 分钟。header=true 参数在此处是必需的,以获取列名。VARIANT 和 OBJECT 列也将 默认 输出为 JSON 字符串,迫使我们在将它们插入 ClickHouse 时进行强制转换。

导入到 ClickHouse

一旦在中间对象存储中暂存,ClickHouse 函数(例如 s3 表函数)可用于将数据插入到表中,如下所示。

假设以下表目标架构

CREATE TABLE default.pypi
(
	`timestamp` DateTime64(6),
	`date` Date MATERIALIZED timestamp,
	`country_code` LowCardinality(String),
	`url` String,
	`project` String,
	`file` Tuple(filename String, project String, version String, type Enum8('bdist_wheel' = 0, 'sdist' = 1, 'bdist_egg' = 2, 'bdist_wininst' = 3, 'bdist_dumb' = 4, 'bdist_msi' = 5, 'bdist_rpm' = 6, 'bdist_dmg' = 7)),
	`installer` Tuple(name LowCardinality(String), version LowCardinality(String)),
	`python` LowCardinality(String),
	`implementation` Tuple(name LowCardinality(String), version LowCardinality(String)),
	`distro` Tuple(name LowCardinality(String), version LowCardinality(String), id LowCardinality(String), libc Tuple(lib Enum8('' = 0, 'glibc' = 1, 'libc' = 2), version LowCardinality(String))),
	`system` Tuple(name LowCardinality(String), release String),
	`cpu` LowCardinality(String),
	`openssl_version` LowCardinality(String),
	`setuptools_version` LowCardinality(String),
	`rustc_version` LowCardinality(String),
	`tls_protocol` Enum8('TLSv1.2' = 0, 'TLSv1.3' = 1),
	`tls_cipher` Enum8('ECDHE-RSA-AES128-GCM-SHA256' = 0, 'ECDHE-RSA-CHACHA20-POLY1305' = 1, 'ECDHE-RSA-AES128-SHA256' = 2, 'TLS_AES_256_GCM_SHA384' = 3, 'AES128-GCM-SHA256' = 4, 'TLS_AES_128_GCM_SHA256' = 5, 'ECDHE-RSA-AES256-GCM-SHA384' = 6, 'AES128-SHA' = 7, 'ECDHE-RSA-AES128-SHA' = 8)
)
ENGINE = MergeTree
ORDER BY (date, timestamp)

由于 Snowflake 将 file 等嵌套结构转换为 JSON 字符串,因此导入此数据需要在 ClickHouse 中使用 JSONExtract 函数 在插入时将这些结构转换为适当的元组,如下所示。

INSERT INTO pypi
SELECT
	TIMESTAMP,
	COUNTRY_CODE,
	URL,
	PROJECT,
	JSONExtract(ifNull(FILE, '{}'), 'Tuple(filename String, project String, version String, type Enum8(\'bdist_wheel\' = 0, \'sdist\' = 1, \'bdist_egg\' = 2, \'bdist_wininst\' = 3, \'bdist_dumb\' = 4, \'bdist_msi\' = 5, \'bdist_rpm\' = 6, \'bdist_dmg\' = 7))') AS file,
	JSONExtract(ifNull(INSTALLER, '{}'), 'Tuple(name LowCardinality(String), version LowCardinality(String))') AS installer,
	PYTHON,
	JSONExtract(ifNull(IMPLEMENTATION, '{}'), 'Tuple(name LowCardinality(String), version LowCardinality(String))') AS implementation,
	JSONExtract(ifNull(DISTRO, '{}'), 'Tuple(name LowCardinality(String), version LowCardinality(String), id LowCardinality(String), libc Tuple(lib Enum8(\'\' = 0, \'glibc\' = 1, \'libc\' = 2), version LowCardinality(String)))') AS distro,
	JSONExtract(ifNull(SYSTEM, '{}'), 'Tuple(name LowCardinality(String), release String)') AS system,
	CPU,
	OPENSSL_VERSION,
	SETUPTOOLS_VERSION,
	RUSTC_VERSION,
	TLS_PROTOCOL,
	TLS_CIPHER
FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/pypi/2023/pypi*.parquet')
SETTINGS input_format_null_as_default = 1, input_format_parquet_case_insensitive_column_matching = 1

我们在此处依赖 input_format_null_as_default=1input_format_parquet_case_insensitive_column_matching=1 设置,以确保在源数据和目标表之间的列匹配不区分大小写的情况下,如果列为 null,则将列作为默认值插入。

如果使用 AzureGoogle Cloud,则可以创建类似的过程。请注意,ClickHouse 中存在用于从这些对象存储导入数据的专用函数 [1][2]

结论

在本文中,我们对比了 Snowflake 和 ClickHouse 在实时分析用例方面的应用,着眼于系统之间的异同。我们确定了对该用例有益的 ClickHouse 功能,并探讨了用户如何从 Snowflake 迁移工作负载。在 本系列的下一篇文章 中,我们将介绍一个示例实时分析应用程序,确定压缩和插入性能方面的差异,并对代表性查询进行基准测试。最后,我们将进行成本分析,在其中介绍使用 ClickHouse Cloud 可能节省的成本。


附录

希望将实时分析工作负载从 Snowflake 迁移到 ClickHouse 的用户可能需要了解几个关键概念。下面,我们提供了有关数据类型以及核心集群和排序中的等效性的其他信息。此信息补充了前面关于传输数据的高级方法的章节。

数据类型

数值类型

在 ClickHouse 和 Snowflake 之间移动数据的用户将立即注意到,ClickHouse 在声明数值类型方面提供了更精细的精度。例如,Snowflake 为数值类型提供了 Number 类型。这要求用户指定精度(总位数)和小数位数(小数点右侧的位数),总共最多 38 位。整数声明与 Number 同义,并且仅定义固定的精度和小数位数,其中范围相同。这种便利性是可能的,因为修改精度(对于整数,小数位数为 0)不会影响 Snowflake 中磁盘上数据的大小 - 在微分区级别,数值范围使用最少的所需字节数。但是,小数位数确实会影响存储空间,并通过压缩来抵消。Float64 类型提供更广泛的值范围,但会损失精度。

与此形成对比的是,ClickHouse 为浮点数和整数提供多种有符号和无符号精度。借助这些精度,ClickHouse 用户可以显式指定整数所需的精度,以优化存储和内存开销。Decimal 类型(相当于 Snowflake 的 Number 类型)也提供两倍的精度和小数位数,即 76 位数字。除了类似的 Float64 值外,当精度不太重要且压缩至关重要时,ClickHouse 还提供 Float32。

字符串类型

ClickHouse 和 Snowflake 在字符串数据存储方面采用了截然不同的方法。Snowflake 中的 VARCHAR 以 UTF-8 格式保存 Unicode 字符,允许用户指定最大长度。此长度对存储或性能没有影响,始终使用最少字节数来存储字符串,而只是提供对下游工具有用的约束。其他类型,例如 Text 和 NChar,只是此类型的别名。相反,ClickHouse 将所有 字符串数据存储为原始字节,类型为 String(无需指定长度),并将编码推迟给用户,并提供 查询时函数 用于不同的编码(动机请参见 此处)。因此,ClickHouse String 在其实现上更类似于 Snowflake Binary 类型。 SnowflakeClickHouse 都支持“排序规则”,允许用户覆盖字符串的排序和比较方式。

半结构化类型

Snowflake 和 ClickHouse 在对半结构化数据的丰富类型支持方面具有可比性,分别通过 VARIANT(实际上是超类型)JSON 类型 提供此类支持。这些类型允许“schema-later”,底层数据类型在插入时由数据库识别。 Snowflake 还支持 ARRAY 和 OBJECT 类型,但这些只是 VARIANT 类型的限制。

ClickHouse 还通过 Nested 类型支持命名元组和元组数组,允许用户显式映射嵌套结构。这允许在整个层次结构中应用编解码器和类型优化,这与 Snowflake 不同,后者要求用户对外部对象使用 OBJECT、VARIANT 和 ARRAY 类型,并且不允许 显式内部类型。这种内部类型也简化了 ClickHouse 中对嵌套数值的查询,这些数值不需要强制转换,并且可以在索引定义中使用。

在 ClickHouse 中,编解码器和优化的类型也可以应用于子结构。这提供了一个额外的好处,即嵌套结构的压缩仍然非常出色,并且与展平数据相当。相比之下,由于无法将特定类型应用于子结构,Snowflake 建议展平数据以实现最佳压缩。 Snowflake 也对这些数据类型施加了大小限制

下面我们映射了从 Snowflake 迁移工作负载到 ClickHouse 的用户的等效类型

SnowflakeClickHouse注意
NUMBERDecimalClickHouse 支持的精度和刻度是 Snowflake 的两倍 - 76 位数字与 38 位数字。
FLOAT, FLOAT4, FLOAT8Float32, Float64Snowflake 中的所有浮点数均为 64 位。
VARCHARString
BINARYString
BOOLEANBool
DATEDate, Date32Snowflake 中的 DATE 提供的日期范围比 ClickHouse 更广,例如,Date32 的最小值是 1900-01-01,Date 的最小值是 1970-01-01。ClickHouse 中的 Date 提供更具成本效益的(两字节)存储。
TIME(N)没有直接等效项,但可以用 DateTimeDateTime64(N) 表示。DateTime64 使用相同的精度概念。
TIMESTAMP - TIMESTAMP_LTZ, TIMESTAMP_NTZ, TIMESTAMP_TZDateTimeDateTime64DateTime 和 DateTime64 可以选择为列定义 TZ 参数。如果不存在,则使用服务器的时区。此外,客户端还可以使用 --use_client_time_zone 参数。
VARIANTJSON, Tuple, NestedJSON 类型在 ClickHouse 中是实验性的。此类型在插入时推断列类型。Tuple、Nested 和 Array 也可用于构建显式类型结构作为替代方案。
OBJECTTuple, Map, JSONOBJECT 和 Map 都类似于 ClickHouse 中的 JSON 类型,其中键是 String。ClickHouse 要求值保持一致且强类型,而 Snowflake 使用 VARIANT。这意味着不同键的值可以是不同的类型。如果 ClickHouse 中需要这样做,请使用 Tuple 显式定义层次结构或依赖 JSON 类型。
ARRAYArray, NestedSnowflake 中的 ARRAY 对元素使用 VARIANT - 一种超类型。相反,这些在 ClickHouse 中是强类型的。
GEOGRAPHYPoint, Ring, Polygon, MultiPolygonSnowflake 强制使用坐标系 (WGS 84),而 ClickHouse 在查询时应用。
GEOMETRYPoint, Ring, Polygon, MultiPolygon

除了上述类型之外,ClickHouse 还提供
  • IP 特定类型 ipv4ipv6,与 Snowflake 相比,可能允许更高效的存储。
  • FixedString - 允许使用固定长度的字节,这对于哈希很有用。
  • LowCardinality - 允许对任何类型进行字典编码。当基数预计小于 10 万时非常有用。
  • Enum - 允许对 8 位或 16 位范围内的命名值进行高效编码。
  • UUID 用于高效存储 uuid。
  • 向量可以表示为 Float32 数组,并支持距离函数。

最后,ClickHouse 提供了存储聚合函数的中间状态的独特能力。此状态是特定于实现的,但允许存储聚合的结果并在以后查询(使用相应的 合并函数)。通常,此功能通过物化视图使用,如下所示,通过存储对插入数据进行查询的增量结果,可以以最小的存储成本快速加速特定查询(更多详细信息请参见 此处)。

立即联系我们,详细了解使用 ClickHouse Cloud 进行实时分析的信息。或者,开始使用 ClickHouse Cloud 并获得 300 美元的信用额度。

分享此帖子

订阅我们的新闻资讯

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