Apache Iceberg™ 表的数据类型¶
Snowflake 支持 Apache Iceberg™ 规范 (https://iceberg.apache.org/spec/) 定义的大部分数据类型,并会将 Iceberg 数据类型写入表文件,以便在您使用 Snowflake 作为目录时,Iceberg 表在不同的计算引擎之间保持互操作性。
有关 Snowflake 支持的 Iceberg 数据类型的概述,请参阅 支持的数据类型。
近似类型¶
如果您的表使用的 Iceberg 数据类型不支持 精确匹配 ,Snowflake 会使用 近似 的 Snowflake 类型。此类型映射会影响使用 Snowflake 作为目录的转换表和 Iceberg 表的列值。
例如,考虑一个包含 Iceberg 类型 int 的列的表。Snowflake 使用 Snowflake 数据类型 NUMBER(10,0) 处理列值。
NUMBER(10,0) 的范围为 (-9,999,999,999, +9,999,999,999),但 int 范围更有限,为 (-2,147,483,648, +2,147,483,647)。如果尝试在该列中插入值 3,000,000,000,则 Snowflake 将返回超出范围的错误消息。
有关近似类型的详细信息,请参阅 支持的数据类型 表中的备注。
支持的数据类型¶
本节中的表显示了 Iceberg 数据类型和 Snowflake 数据类型之间的关系。它们使用以下列:
- Iceberg 类型:
Apache Iceberg 规范中定义的数据类型。使用 Snowflake 作为目录时,Snowflake 会将 Iceberg 类型写入表数据文件,以便表在不同的计算引擎之间保持互操作性。
- Snowflake 类型:
用于处理和返回表数据的 Snowflake 数据类型。例如,如果架构指定了 Iceberg 类型
timestamp,则 Snowflake 将使用 Snowflake 数据类型 TIMESTAMP_NTZ(6) 以微秒精度处理并返回值。- 备注:
其他使用说明,包括有关使用 近似类型 的说明。
数值类型¶
使用 Snowflake 作为目录¶
下表显示了对于使用 Snowflake 作为 Iceberg 目录的表(由 Snowflake 管理的表),Iceberg 数值数据类型如何映射到 Snowflake 数值数据类型。 当您创建 Snowflake 管理的 Iceberg 表时,可使用 Iceberg 数据类型 (https://iceberg.apache.org/spec/#schemas-and-data-types) 来定义数值列。
Iceberg 数据类型 |
Snowflake 数据类型 |
备注 |
|---|---|---|
:code:`int`(32 位带符号整数) |
如果插入的 10 位数小于最小值,或大于最大的 32 位带符号整数值,则会导致超出范围错误。 |
|
:code:`long`(64 位带符号整数) |
如果插入的 19 位数小于最小值,或大于最大的 64 位带符号整数值,则会导致超出范围错误。 |
|
:code:`float`(单精度 32 位 IEEE 754 浮点) |
与 Snowflake DOUBLE 数据类型同义。Snowflake 将所有浮点数都视为双精度 64 位浮点数,但会将 Iceberg 浮点数作为 32 位浮点数写入表数据文件。 将转换从 64 位缩窄到 32 位会导致精度损失。 您不能使用 |
|
:code:`double`(双精度 64 位 IEEE 754 浮点) |
与 Snowflake DOUBLE 数据类型同义。Snowflake 将所有浮点数都视为双精度 64 位浮点数。 将转换从 64 位缩窄到 32 位会导致精度损失。 您不能使用 |
|
|
指定 |
外部目录¶
当您创建使用外部 Iceberg 目录的 Iceberg 表时,Iceberg 数值类型将根据下表映射到 Snowflake 数值类型。
Iceberg 数据类型 |
Snowflake 数据类型 |
|---|---|
:code:`int`(32 位带符号整数) |
|
:code:`long`(64 位带符号整数) |
|
:code:`float`(单精度 32 位 IEEE 754 浮点) |
|
:code:`double`(双精度 64 位 IEEE 754 浮点) |
|
|
备注
您不能使用 float 或 double 作为主键(根据 Apache Iceberg 规范 (https://iceberg.apache.org/spec/#identifier-field-ids))。
其他数据类型¶
备注
对于非数值数据类型,当您使用 Snowflake 作为目录时,请在表 DDL 中指定 Snowflake 数据类型(例如,使用结构化 ARRAY 而非 list 类型)。Snowflake 会自动将每种 Snowflake 类型映射到表元数据中相应的 Iceberg 数据类型,以便与外部 Iceberg 工具实现互操作性。
Iceberg 数据类型 |
Snowflake 数据类型 |
备注 |
|---|---|---|
|
||
|
||
|
基于 Apache Iceberg 表规范的微秒级精度。 |
|
|
基于 Apache Iceberg 表规范的微秒级精度。 您还可以使用 Parquet 物理类型 |
|
|
基于 Apache Iceberg 表规范的微秒级精度。 您还可以使用 Parquet 物理类型 |
|
|
默认大小为 128 MB,唯一可以明确指定的大小是 134217728 (128 MB)。 |
|
|
||
|
结构化类型列最多支持 1000 个子列。 |
|
|
结构化类型列最多支持 1000 个子列。 |
|
|
结构化类型列最多支持 1000 个子列。 |
Iceberg v3 数据类型¶
重要
要使用 Iceberg v3 数据类型,必须将 Iceberg 表符合的 Apache Iceberg™ 规范版本指定为 3。有关如何指定版本的说明,请参阅 配置默认 Iceberg 版本。
下表显示了可用于 Iceberg 表的 Apache Iceberg™ v3 数据类型:
Iceberg 数据类型 |
Snowflake 数据类型 |
备注 |
|---|---|---|
|
|
Snowflake 支持在 Apache Iceberg™ 表 中使用 GEOGRAPHY 数据类型。您可以创建包含 GEOGRAPHY 列的 Snowflake 管理或外部管理的 Iceberg 表。要创建具有 GEOGRAPHY 列的 Iceberg 表,请使用 CREATE ICEBERG TABLE 命令。 小心 Iceberg 使用 WKB 格式来存储地理数据。此格式无法表示 Snowflake GEOGRAPHY 值中可以包含的所有数据。WKB 格式不支持 对于 GEOGRAPHY 对象,SRID 始终为 4326。 |
|
|
Snowflake 支持在 Apache Iceberg™ 表 中使用 GEOMETRY 数据类型。您可以创建包含 GEOMETRY 列的 Snowflake 管理或外部管理的 Iceberg 表。要创建具有 GEOMETRY 列的 Iceberg 表,请使用 CREATE ICEBERG TABLE 命令。 备注 单列中的所有 GEOMETRY 对象必须具有相同的 SRID。 |
|
|
根据 Apache Iceberg 表规范,精度为纳秒级。无时区语义(挂钟)。TIMESTAMP(9) 首先根据 Snowflake 参数 TIMESTAMP_TYPE_MAPPING 的值,映射到 TIMESTAMP_NTZ(9) 或 TIMESTAMP_LTZ(9) Snowflake 类型。然后,将其映射到适当的 Iceberg 数据类型。 |
|
|
根据 Apache Iceberg 表规范,精度为纳秒级。存储在 UTC 中。 TIMESTAMP(9) 首先根据 Snowflake 参数 TIMESTAMP_TYPE_MAPPING 的值,映射到 TIMESTAMP_NTZ(9) 或 TIMESTAMP_LTZ(9) Snowflake 类型。然后,将其映射到适当的 Iceberg 数据类型。 |
|
Snowflake 最初为标准 Snowflake 表开发了 VARIANT 数据类型。 VARIANT 为 JSON、Avro、Protobuf 等动态半结构化数据提供高效的二进制编码,使处理和操作包含其他嵌套数据类型的数据变得更加容易。有关更多信息,请参阅 半结构化数据类型 和 。 粉碎 Snowflake 为 VARIANT 数据类型提供内置粉碎(也称为 子列化)。粉碎是将 VARIANT 类型列中的字段提取到独立字段中,并以列式形式(子列)进行存储的过程,以便您可以使用特殊符号进行遍历和查询。 Snowflake 跟踪已粉碎子列的元数据和统计信息,从而通过查询剪枝实现更快、更高效的查询。 当您将半结构化数据插入 VARIANT 列时,Snowflake 会尽可能多地粉碎数据。 有关更多信息,请参阅 半结构化数据文件和子列化。 |
Iceberg v3 数据类型的注意事项¶
使用 Iceberg v3 数据类型时,请考虑以下事项:
纳秒时间戳
nanosecond timestamps数据类型的使用说明:在 CREATE ICEBERG TABLE 和 ALTER ICEBERG TABLE 语句使用 TIMESTAMP_NTZ(9)、TIMESTAMP_LTZ(9) 或 TIMESTAMP(9)。
9的标度指定了一种新的 Iceberg 纳秒类型。6的标度仍然指定传统的微秒类型。省略标度时,会话级参数
ICEBERG_TIMESTAMP_DEFAULT_SCALE控制精度。保留默认值6以确保兼容性。如果希望 Iceberg 时间戳列默认为纳秒,请将参数设置为9。所有标准 Iceberg 分区转换(例如,身份、桶、年、月、日和小时)都接受新的纳秒类型,就像接受微秒变体一样。
兼容性
读/写 – Snowflake 管理的和外部管理的 Iceberg 表都支持读取和写入操作。
外部工具 – 无需更改连接器。纳秒值在读取和写入操作中用作标准 Iceberg
timestamp_ns和timestamptz_ns值。
VARIANT
在将
VARIANT数据类型与 Iceberg 表一起使用时,请考虑以下注意事项和限制:
Iceberg 数据类型的常规注意事项适用于 VARIANT 数据类型。有关更多信息,请参阅 使用 Iceberg 表数据类型的注意事项。
VARIANT 列对象的键应为类型 STRING。
支持使用 Snowpipe 或 COPY INTO 将数据加载到具有 Variant 列的 Iceberg 表中。但是,Snowpipe 和 COPY INTO 不能用于将数据加载到包含嵌套 Variant 列的 OBJECT、ARRAY 或 MAP 列。
不支持嵌套变体。
示例¶
以下部分包含 Iceberg v3 数据类型的示例。
GEOGRAPHY¶
要将数据插入到 GEOGRAPHY 列中,请指定输入数据。以下示例将一个以常用文本 (WKT) 定义的地理空间对象插入到前一示例创建的 geog_points 表的 geog 列中:
INSERT INTO geog_points
SELECT TO_GEOGRAPHY('POINT(-122.3861109 37.61637595)');
您还可以插入地理空间数据,而无需显式构造 GEOGRAPHY 值:
INSERT INTO geog_points
SELECT 'POINT(-122.3861109 37.61637595)';
GEOMETRY¶
以下示例创建了一个空的 Iceberg 表,其中包含一个名为 geom 的 GEOMETRY 列,SRID 的默认值为 4326。
CREATE ICEBERG TABLE geo_points (geom GEOMETRY)
CATALOG = 'SNOWFLAKE'
EXTERNAL_VOLUME = 'my_external_volume'
BASE_LOCATION = 'us_states'
ICEBERG_VERSION = 3;
您还可以在 DDL 语句中显式设置 SRID。以下示例将 SRID 设置为 4269:
CREATE ICEBERG TABLE geo_points (geom GEOMETRY(4269))
CATALOG = 'SNOWFLAKE'
EXTERNAL_VOLUME = 'my_external_volume'
BASE_LOCATION = 'us_states'
ICEBERG_VERSION = 3;
要将数据插入到 GEOMETRY 列中,请指定输入数据。以下示例将一个以常用文本 (WKT) 定义的地理空间对象插入到上一示例创建的 geo_points 表的 geom 列中。
INSERT INTO geo_points
SELECT TO_GEOMETRY('POINT(-122.3861109 37.61637595)');
您还可以插入地理空间数据,而无需显式构造 GEOMETRY 值:
INSERT INTO geo_points
SELECT 'POINT(-122.3861109 37.61637595)';
如果 SRID 不作为 GEOMETRY 对象的一部分,您可以使用构造函数显式设置它:
INSERT INTO geo_points
SELECT TO_GEOMETRY('POINT(-122.3861109 37.61637595)', 4326);
纳秒时间戳¶
以下示例创建了一个具有纳秒时间戳的托管 Iceberg 表:
CREATE ICEBERG TABLE sensor_readings (
reading_ntz TIMESTAMP_NTZ(9),
reading_ltz TIMESTAMP_LTZ(9))
ICEBERG_VERSION = 3;
对于此语句,Snowflake 执行以下数据类型映射:
reading_ntz列的数据类型映射到timestamp_nsIceberg v3 数据类型。reading_ltz列的数据类型映射到timestamptz_nsIceberg v3 数据类型。
VARIANT¶
您可以使用 CREATE ICEBERG TABLE 命令创建包含 VARIANT 列的 Iceberg 表。
以下示例创建了一个 Snowflake 管理的空 Iceberg 表,其中包含一个名为 record 的 VARIANT 列。
CREATE ICEBERG TABLE car_sales (record VARIANT)
CATALOG = 'SNOWFLAKE'
EXTERNAL_VOLUME = 'my_external_volume'
BASE_LOCATION = 'car_sales'
ICEBERG_VERSION = 3;
同样,以下示例在目录链接数据库中创建一个空的、外部管理的 Iceberg 表,Snowflake 可以向该表执行写入操作。
USE DATABASE my_catalog_linked_db;
USE SCHEMA my_namespace;
CREATE ICEBERG TABLE car_sales (record VARIANT)
ICEBERG_VERSION = 3;
要将数据插入到 VARIANT 列中,请指定输入数据格式。以下示例使用 PARSE_JSON 函数将 JSON 格式的数据插入到先前创建的 car_sales 表的 record 列中。
INSERT INTO car_sales SELECT
PARSE_JSON(
'{
"date" : "2017-04-28",
"dealership" : "Valley View Auto Sales",
"salesperson" : {
"id": "55",
"name": "John Salesperson"
},
"customer" : [
{"name": "Alice Doe", "phone": "14151234567", "address": "San Francisco, CA"},
{"name": "Bob Doe", "phone": "14151234567", "address": "San Francisco, CA"}
],
"vehicle" : [
{"make": "Honda", "model": "Civic", "year": "2017", "price": "20275", "extras":["ext warranty", "paint protection"]}
]
}'
);
对该表运行 SELECT * FROM 语句将返回以下输出:
+--------------------------------------------+
| RECORD |
|--------------------------------------------|
| { |
| "customer": [ |
| { |
| "address": "San Francisco, CA", |
| "name": "Alice Doe", |
| "phone": "14151234567" |
| }, |
| { |
| "address": "San Francisco, CA", |
| "name": "Bob Doe", |
| "phone": "14151234567" |
| } |
| ], |
| "date": "2017-04-28", |
| "dealership": "Valley View Auto Sales", |
| "salesperson": { |
| "id": "55", |
| "name": "John Salesperson" |
| }, |
| "vehicle": [ |
| { |
| "extras": [ |
| "ext warranty", |
| "paint protection" |
| ], |
| "make": "Honda", |
| "model": "Civic", |
| "price": "20275", |
| "year": "2017" |
| } |
| ] |
| } |
+--------------------------------------------+
要查询 VARIANT 列中的数据,您可以使用点或括号表示法来访问数据中嵌套的元素。
以下示例使用点表示法来获取所有销售汽车的销售人员的姓名。由于表中只有一行,因此查询会生成单个结果值。
SELECT record:salesperson.name
FROM car_sales
ORDER BY 1;
输出:
+-------------------------+
| RECORD:SALESPERSON.NAME |
|-------------------------|
| "John Salesperson" |
+-------------------------+
有关查询半结构化数据的详细信息,请参阅 查询半结构化数据。
备注
使用 Apache Spark 读取或写入包含 Variant 列的 Iceberg 表时,必须使用 Apache Spark 4.0 或更高版本(该版本包含对 Variant 的支持)。
Snowflake 管理的 Iceberg 表中的 Variant 列可以由支持 Iceberg Variant 的引擎(如 Apache Spark)读取。引擎可以通过 Horizon Iceberg REST 目录 API 读取 Snowflake 管理的 Iceberg v3 表。
spark.sql(""" SELECT variant_get(record, '$.customer[0].name', 'string') AS customer_1_name variant_get(record, '$.salesperson.name', 'string') AS name FROM CAR_SALES ORDER BY name """).show()
同样,Snowflake 可以读取或写入包含 Variant 列的外部管理 Iceberg 表。
如果需要,Snowflake 可以将空值 (NULL) 写入表。
例如:
INSERT INTO my_table_new SELECT ARRAY_CONSTRUCT( OBJECT_CONSTRUCT_KEEP_NULL('field1', NULL, 'field2', 123) )::ARRAY(OBJECT(field1 STRING, field2 INT));
Delta 数据类型¶
下表显示了对于 从Delta 表文件创建的 Iceberg 表,如何将 Delta 数据类型映射到 Snowflake 数据类型。
Delta 类型 |
Snowflake 数据类型 |
备注 |
|---|---|---|
BINARY |
BINARY |
|
BOOLEAN |
BOOLEAN |
|
BYTE |
NUMBER (3,0) |
|
DATE |
DATE |
|
DECIMAL (P,S) |
NUMBER (P,S) |
|
DOUBLE |
REAL |
|
FLOAT |
REAL |
|
INTEGER |
NUMBER (10,0) |
|
LONG |
NUMBER (20,0) |
|
SHORT |
NUMBER (5,0) |
|
STRING |
TEXT |
|
TIMESTAMP |
TIMESTAMP_LTZ (6) |
您还可以为 TIMESTAMP 使用 Parquet 物理类型 |
TIMESTAMP_NTZ |
TIMESTAMP_NTZ (6) |
下表显示了 Delta 嵌套数据类型如何映射到 Snowflake 数据类型。
Delta 嵌套类型 |
Snowflake 数据类型 |
|---|---|
STRUCT |
|
ARRAY |
|
MAP |
注意事项¶
使用 Iceberg 表的数据类型时,请注意以下事项:
-
uuidfixed(L)
对于使用 Snowflake 作为目录的表,不支持创建使用 Iceberg
uuid数据类型的表。对于使用外部目录的表,您无法创建具有结构化类型列的 Iceberg v3 表,这些结构化类型包括 OBJECT、ARRAY 或 MAP。例如,您不能使用 CREATE ICEBERGTABLE … ASSELECT (CTAS) 创建具有结构化类型列的外部管理的 Iceberg v3 表。
您可以使用结构化类型列创建 Snowflake 管理的 Iceberg v3 表。
适用于所有 Iceberg 表类型:
结构化类型列最多支持 1000 个子列。
对于时间和时间戳类型,Iceberg 支持微秒精度。因此,您无法在 Snowflake 中创建使用其他精度(如毫秒或纳秒)的 Iceberg 表。
您不能使用
float或double作为主键(根据 Apache Iceberg 规范 (https://iceberg.apache.org/spec/#identifier-field-ids))。对于使用
LIST逻辑类型的 Parquet 文件,请注意以下几点:支持带
element关键字的三级注释结构。有关更多信息,请参阅 ` Parquet 逻辑类型定义 <https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#lists (https://github.com/apache/parquet-format/blob/master/LogicalTypes.md#lists)>`_。如果您的 Parquet 文件使用带array关键字的过时格式,您必须根据支持的格式重新生成数据。
对于从 Delta 文件创建的表,请注意以下几点:
不支持使用以下任何功能或数据类型的 Parquet 文件(Delta 表的数据文件):
字段 IDs。
INTERVAL 数据类型。
精度高于 38 的 DECIMAL 数据类型。
LIST 或 MAP 类型的一级或两级表示。
无符号整型 (INT(signed = false))。
FLOAT16 数据类型。
您可以为 TIMESTAMP 使用 Parquet 物理类型
int96,但 Snowflake 不支持为 TIMESTAMP_NTZ 使用int96。