跳到主要内容
跳到主要内容

Snowflake SQL 转换指南

数据类型

数值类型

在 ClickHouse 和 Snowflake 之间迁移数据的用户会立刻注意到,ClickHouse 在数值类型声明方面提供了更细粒度的精度控制。比如,Snowflake 为数值提供了 Number 类型。这要求用户指定精度(数字总位数)和标度(小数点右侧的位数),两者之和最多为 38。整数声明等同于 Number,只是定义了一个固定的精度和标度,且取值范围相同。之所以可以这样做,是因为在 Snowflake 中修改精度(整数的标度为 0)不会影响磁盘上的数据大小——在微分区级别写入时,会为给定数值范围使用所需的最小字节数。不过,标度确实会影响存储空间,但可以通过压缩进行抵消。Float64 类型提供了更宽的取值范围,但会牺牲精度。

与此相对,ClickHouse 为浮点数和整数提供了多种有符号与无符号类型和精度选项。借助这些类型,ClickHouse 用户可以明确指定整数所需的精度,以优化存储和内存开销。Decimal 类型相当于 Snowflake 的 Number 类型,但在 76 位数字上提供了两倍的精度和标度。除了类似的 Float64 类型外,ClickHouse 还提供了 Float32,适用于精度要求较低、压缩优先的场景。

字符串

ClickHouse 和 Snowflake 在字符串数据存储方式上采取了截然不同的策略。Snowflake 中的 VARCHAR 以 UTF-8 存储 Unicode 字符,允许用户指定最大长度。该长度对存储或性能没有影响,始终使用存储字符串所需的最少字节数,只是为下游工具提供有用的约束。其他类型,例如 TextNChar,只是该类型的别名。相反,ClickHouse 使用 String 类型(不需要指定长度)将所有字符串数据以原始字节形式存储,将编码交由用户控制,并提供适用于不同编码的查询时函数。关于背后的动机,我们推荐读者参考 "Opaque data argument"。因此,在实现上,ClickHouse 的 String 更接近于 Snowflake 的 Binary 类型。SnowflakeClickHouse 均支持“排序规则(collation)”,允许用户自定义字符串的排序与比较方式。

半结构化类型

Snowflake 为半结构化数据提供了 VARIANTOBJECTARRAY 类型。

ClickHouse 提供了等价的 VariantObject(现已弃用,推荐使用原生 JSON 类型)以及 Array 类型。此外,ClickHouse 还提供了 JSON 类型,用于取代现已弃用的 Object('json') 类型,并且在与其他原生 JSON 类型的对比中表现出特别优越的性能和存储效率。

ClickHouse 还支持具名的 Tuple 以及通过 Nested 类型实现的 Tuple 数组,使用户可以显式映射嵌套结构。这样可以在整个层级结构中应用编解码器和类型优化;而 Snowflake 则要求用户在外层对象上使用 OBJECTVARIANTARRAY 类型,并且不允许显式指定内部类型。这种内部类型定义也简化了在 ClickHouse 中对嵌套数值的查询,这些数值无需强制类型转换即可用于索引定义。

在 ClickHouse 中,编解码器和优化类型同样可以应用到子结构上。这带来的额外好处是,嵌套结构下的压缩效果依然非常出色,并且与扁平化数据相当。相比之下,由于无法对子结构应用特定类型,Snowflake 建议通过扁平化数据以获得最佳压缩效果。Snowflake 还对这些数据类型施加了大小限制

类型参考

SnowflakeClickHouse注意
NUMBERDecimalClickHouse 所支持的精度和小数位数是 Snowflake 的两倍——可达 76 位数字,而 Snowflake 为 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_TZDateTimeDateTime64DateTimeDateTime64 列可以可选地定义一个 TZ 参数。若未指定,则使用服务器的时区。此外,客户端还可以使用 --use_client_time_zone 参数。
VARIANTJSON, Tuple, NestedClickHouse 中的 JSON 类型目前是实验性特性。该类型会在插入数据时推断列的类型。也可以使用 TupleNestedArray 来显式构建具有明确类型的结构,作为替代方案。
OBJECTTuple, Map, JSONOBJECTMap 都类似于 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 TypeDescription
IPv4 and IPv6面向 IP 的专用数据类型,相比 Snowflake 可能支持更高效的存储。
FixedString允许使用固定字节长度,对存储哈希值非常有用。
LowCardinality允许对任意类型进行字典编码,适用于基数预期小于 100k 的场景。
Enum允许在 8 或 16 位范围内对具名值进行高效编码。
UUID用于高效存储 UUID。
Array(Float32)向量可以表示为由 Float32 组成的 Array,并支持距离函数。

最后,ClickHouse 提供了一个独特的能力,即存储聚合函数的中间 状态。这一状态依赖具体实现, 但它允许将聚合结果存储起来,并在之后通过相应的合并函数进行查询。通常,这一 特性是通过物化视图来使用的,并且如下面所示,可以在仅增加极少量存储成本的情况 下,通过存储针对已插入数据的查询增量结果(更多细节见后文)来提升特定查询的性能。