Dynamic 类型的列,请使用以下语法:
N 是一个介于 0 到 254 之间的可选参数,用于指定在单个独立存储的数据块中 (例如,对于 MergeTree 表,即单个数据分区片段中) ,Dynamic 类型的列最多可将多少种不同的数据类型作为独立子列存储。如果超过此限制,所有新类型的值都会以二进制形式统一存储在一种特殊的共享数据结构中。max_types 的默认值为 32。
创建 Dynamic
Dynamic 类型:
Variant 列使用 CAST:
将 Dynamic 嵌套类型读取为子列
Dynamic 类型支持将类型名称用作子列,从 Dynamic 列中读取单个嵌套类型。
因此,如果你有一列 d Dynamic,就可以使用语法 d.T 读取任意有效类型 T 的子列。
如果 T 可以包含在 Nullable 中,则该子列的类型为 Nullable(T);否则类型为 T。该子列的大小将
与原始 Dynamic 列相同,并且在原始 Dynamic 列不属于类型 T 的所有行中,其值将为 NULL (如果 T 不能包含在 Nullable 中,则为空值) 。
Dynamic 子列也可以通过函数 `dynamicElement(dynamic_column, type_name)“ 读取。
示例:
dynamicType(dynamic_column)。它会为每一行返回一个 String,其值为该行的类型名称 (如果该行为 NULL,则返回 'None') 。
示例:
Dynamic 列与其他列之间的转换
Dynamic 列与其他列之间共有 4 种可能的转换方式。
将普通列转换为 Dynamic 列
通过解析将 String 列转换为 Dynamic 列
String 列解析出 Dynamic 类型的值,可以启用设置 cast_string_to_dynamic_use_inference:
将 Dynamic 列转换为普通列
Dynamic 列转换为普通列。在这种情况下,所有嵌套类型都会转换为目标类型:
将 Variant 列转换为 Dynamic 列
将 Dynamic(max_types=N) 列转换为另一个 Dynamic(max_types=K)
K >= N,那么转换过程中数据不会发生变化:
K < N,则具有最少见类型的值会被插入到一个特殊的子列中,但仍可访问:
isDynamicElementInSharedData 会对存储在 Dynamic 内部特殊共享数据结构中的行返回 true。正如我们所见,结果列中只包含 2 种未存储在共享数据结构中的类型。
如果 K=0,所有类型都会被插入到单个特殊子列中:
从数据中读取 Dynamic 类型
Dynamic 类型。解析数据时,ClickHouse 会尝试推断每个值的类型,并在插入到 Dynamic 列时使用该类型。
示例:
在函数中使用 Dynamic 类型
Dynamic 类型的参数。在这种情况下,函数会针对 Dynamic 列中存储的每种内部数据类型分别执行。
当函数的结果类型取决于参数类型时,以 Dynamic 参数执行该函数所得的结果类型也将为 Dynamic。当函数的结果类型与参数类型无关时,结果类型将为 Nullable(T),其中 T 为该函数通常的返回类型。
示例:
Dynamic 列中的某些类型上执行,则会抛出异常:
类型不匹配时的行为
dynamic_throw_on_type_mismatch 用于控制:当某个函数应用于 Dynamic 列,而某一行实际存储的类型与该函数不兼容时,会如何处理:
true(默认) — 在遇到第一行不兼容的行时抛出异常 (ILLEGAL_TYPE_OF_ARGUMENT) 。false— 对不兼容的行返回NULL,同时保留兼容行的结果。
在 ORDER BY 和 GROUP BY 中使用 Dynamic 类型
ORDER BY 和 GROUP BY 中,Dynamic 类型的值会以与 Variant 类型值类似的方式进行比较:
对于 Dynamic 类型中底层类型为 T1 的值 d1 和底层类型为 T2 的值 d2,运算符 < 的结果定义如下:
- 如果
T1 = T2 = T,结果为d1.T < d2.T(比较底层值) 。 - 如果
T1 != T2,结果为T1 < T2(比较类型名称) 。
Dynamic 类型不允许用于 GROUP BY/ORDER BY 键;如果要使用它,请留意其特殊的比较规则,并启用 allow_suspicious_types_in_group_by/allow_suspicious_types_in_order_by 设置。
示例:
Dynamic 类型的函数有其特殊处理机制,上述比较规则不会应用于执行 </>/= 等比较函数时
Dynamic 中存储的不同数据类型数量达到上限
Dynamic 数据类型只能将有限数量的不同数据类型作为独立子列存储。默认情况下,这个上限为 32,但你可以在类型声明中使用语法 Dynamic(max_types=N) 进行修改,其中 N 的取值范围为 0 到 254 (由于实现细节的限制,Dynamic 中作为独立子列存储的不同数据类型不可能超过 254 种) 。
当达到该上限时,所有新插入到 Dynamic 列中的数据类型都会被写入一个共享数据结构中,该结构以二进制形式存储不同数据类型的值。
下面来看一下,在不同场景下达到该上限时会发生什么。
在数据解析过程中达到限制
Dynamic 值时,如果当前数据块已达到限制,所有新值都将插入共享数据结构中:
Int64、Array(Int64) 和 String 后,所有新类型都会被插入到特殊的共享数据结构中。
在 MergeTree 表引擎中合并数据分区片段时
Dynamic 列可能会达到其内部可作为独立子列存储的不同数据类型数量上限,因此无法将源数据分区片段中的所有类型都作为子列存储。
在这种情况下,ClickHouse 会决定哪些类型在合并后继续保留为独立子列,哪些类型会被写入共享数据结构。大多数情况下,ClickHouse 会尽量保留最常见的类型,并将最少见的类型存入共享数据结构,但具体仍取决于实现方式。
下面来看一个这样的合并示例。首先,创建一个带有 Dynamic 列的表,将不同数据类型的数量上限设置为 3,然后插入包含 5 种不同类型的值:
Dynamic 列仅包含一种类型:
UInt64 和 Array(UInt64) 保留为子列,而将所有其他类型都写入共享数据中。
支持 Dynamic 的 JSONExtract 函数
JSONExtract* 函数都支持 Dynamic 类型:
二进制输出格式
Dynamic 类型的值按以下格式进行序列化: