数据加载概述

本主题概述了可用于将数据加载到 Snowflake 的主要选项。

要轻松准确地测量数据管道的引入延迟,请使用行时间戳。有关更多信息,请参阅 使用行时间戳测量管道中的延迟

支持的文件位置

Snowflake 将数据文件在云存储中的位置称为 暂存区COPY INTO <table> 命令用于批量和连续数据加载 (Snowpipe),它支持由您的业务实体管理的云存储账户(外部暂存区)以及 Snowflake 账户中包含的云存储(内部暂存区)。

外部暂存区

无论托管 Snowflake 账户的 云平台 如何,均支持从以下任何云存储服务加载数据:

  • Amazon S3

  • Google Cloud Storage

  • Microsoft Azure

您不能访问存档云存储类别中保存的数据,这些数据需要恢复后才能检索。例如,这些存档存储类别包括 Amazon S3 Glacier Flexible Retrieval 或 Glacier Deep Archive 存储类别,或者 Microsoft Azure Archive Storage。

使用云存储服务提供的工具将文件上传(即 暂存)到您的云存储账户。

指定的外部暂存区是在架构中创建的数据库对象。此对象存储云存储中文件的 URL、用于访问云存储账户的设置以及便捷性设置,如描述暂存文件格式的选项。使用 CREATE STAGE 命令创建暂存区。

备注

在加载数据时,如果数据来源是不同于 Snowflake 账户的区域或云平台的云存储服务中的文件,您可能要支付某些数据传输费用。有关更多信息,请参阅 了解数据传输成本

内部暂存区

Snowflake 在您的账户中维护以下暂存区类型:

用户:

为每个用户分配一个用户暂存区,供其存储文件。此暂存区类型旨在存储由单个用户暂存和管理,但可能加载到多个表中的数据。无法更改或删除用户暂存区。

:

在 Snowflake 中创建的每个表都有一个表暂存区。此暂存区类型旨在存储由一个或多个用户暂存和管理,但仅加载到单个表中的文件。表暂存区不能更改或删除。

请注意,表暂存区不是一个单独的数据库对象;相反,它是与表本身绑定的隐式暂存区。表暂存区本身没有可授予的权限。要将文件暂存到表暂存区、列出文件、在暂存区中查询文件或删除文件,您必须是表所有者(拥有对表具有 OWNERSHIP 权限的角色)。

命名:

指定的内部暂存区是在架构中创建的数据库对象。此暂存区类型可存储由一个或多个用户暂存和管理,且加载到一个或多个表中的文件。指定暂存区是数据库对象,因此可以使用安全访问控制权限来控制创建、修改、使用或删除它们的能力。使用 CREATE STAGE 命令创建暂存区。

使用 PUT 命令可将文件从本地文件系统上传到任何类型的内部暂存区。

批量加载与连续加载的对比

Snowflake 提供了以下主要数据加载解决方案。最合适的解决方案可能取决于要加载的数据量和加载频率。

使用 COPY 命令批量加载

此选项允许从云存储中已有的文件批量加载数据,或将数据文件从本地计算机复制(即 暂存)到内部(即 Snowflake)云存储位置,然后再使用 COPY 类型将数据加载到表中。

计算资源

批量加载依赖于用户提供的虚拟仓库,这些虚拟仓库在 COPY 语句中指定。用户需要适当调整仓库的大小,以适应预期负载。

加载期间的简单转换

Snowflake 支持将数据加载到表中时使用 COPY 命令转换数据。选项包括:

  • 重新排序列

  • 忽略列

  • 强制类型转换

  • 截断超过目标列长度的文本字符串

您的数据文件不需要与目标表具有相同的列数和顺序。

使用 Snowpipe 连续加载

此选项旨在加载少量数据(即微批处理),并以增量形式使其可用于分析。在将文件添加到暂存区并提交以供引入后,Snowpipe 会在几分钟内加载数据。这可确保用户在原始数据可用后立即获得最新的结果。

计算资源

Snowpipe 使用 Snowflake 提供的计算资源(即无服务器计算模型)。这些 Snowflake 提供的资源会按需自动调整规模,并纵向扩展或缩减,并使用按秒计费的方式进行计费和列举明细。数据引入根据实际工作负载进行收费。

加载期间的简单转换

管道定义中的 COPY 语句支持与批量加载数据时相同的 COPY 转换选项。

此外,数据管道可以利用 Snowpipe,将微批量数据持续加载到暂存表中,以便使用自动任务和流中的变更数据获取 (CDC) 信息进行转换和优化。

使用 Snowpipe Streaming 进行连续加载

Snowpipe Streaming API 将数据行直接写入 Snowflake 表,而无需暂存文件。这种架构可降低加载延迟,并相应降低加载任何数据量的费用,因此是处理近乎实时数据流的强大工具。

Snowpipe Streaming 还可用于 Snowflake Connector for Kafka,它提供了简单的升级路径,以利用更低的延迟和更低的成本负载。

有关更多信息,请参阅 Snowpipe Streaming

从 Apache Kafka 主题加载数据

Snowflake Connector for Kafka 让用户能够连接到 Apache Kafka (https://kafka.apache.org/) 服务器,从一个或多个主题中读取数据,并将该数据加载到 Snowflake 表中。

DML 错误日志记录

当您执行一组 DML 语句,并且其中一个语句因错误而失败,则 DML 操作结束,DML 语句所做的更改已回滚。如果要继续执行 DML 语句的其余部分并记录发生的错误,您可以为表开启 DML 错误日志记录。为其开启 DML 错误日志记录的表称为 基表。错误记录在与基表关联的 错误表 中。

仅当满足以下 两个 条件时,才会为表开启 DML 错误日志记录:

  • 表的 ERROR_LOGGING 属性设置为 TRUE

  • 当前会话的 OPT_OUT_ERROR_LOGGING 参数设置为 FALSE

仅当满足以下 任一 条件时,才会为表关闭 DML 错误日志记录:

  • 表的 ERROR_LOGGING 属性设置为 FALSE

  • 当前会话的 OPT_OUT_ERROR_LOGGING 参数设置为 TRUE

以下部分提供了有关 DML 错误日志记录的更多信息:

DML 错误日志记录用例

在以下用例中,可通过 DML 错误日志记录避免因错误而导致的失败:

  • 依赖于 DML 错误日志记录的第三方数据迁移,例如来自 Oracle 数据库的数据。

  • 在数据引入期间强制执行某些表约束条件,例如 NOT NULL 约束条件。

为表配置 DML 错误日志记录

在创建或修改表时,您可以为标准 Snowflake 表或 Snowflake 管理的 Iceberg 表开启或关闭 DML 错误日志记录。

要为表开启或关闭错误日志记录,请使用以下 SQL 命令来为表设置 ERROR_LOGGING 属性:

  • CREATE TABLE

  • ALTER TABLE

  • :doc:`/sql-reference/sql/create-iceberg-table`(仅限 Snowflake 管理)

  • :doc:`/sql-reference/sql/alter-iceberg-table`(仅限 Snowflake 管理)

以下示例为表配置 DML 错误日志记录,并显示如何在错误表中记录错误:

以下示例为表配置 DML 错误日志记录,并显示如何在错误表中记录错误:

记录直接插入行时出现的错误

以下示例记录了直接向表中插入行时出现的错误:

  1. 创建表并为其开启 DML 错误日志记录:

    CREATE TABLE test_dml_error_logging(
      n NUMBER(4, 0) NOT NULL,
      t VARCHAR(5)
      )
      ERROR_LOGGING = true;
    
  2. 运行尝试插入多行(包括有效值和无效值)的 INSERT 语句:

    INSERT INTO test_dml_error_logging
      VALUES
        ('invalid_cast', '1'),
        (10, 'valid'),
        (NULL, 'toolong');
    
    +-------------------------+
    | number of rows inserted |
    |-------------------------|
    |                       1 |
    +-------------------------+
    
  3. 查询表以确认插入了有效行:

    SELECT * FROM test_dml_error_logging;
    
    +----+-------+
    |  N | T     |
    |----+-------|
    | 10 | valid |
    +----+-------+
    
  4. 查询 test_dml_error_logging 基表的错误表,以查看记录的错误:

    SELECT * FROM ERROR_TABLE(test_dml_error_logging);
    
    +-------------------------------+--------------------------------------+------------+----------------------------------------------------------------------+--------------------+
    | TIMESTAMP                     | QUERY_ID                             | ERROR_CODE | ERROR_METADATA                                                       | ERROR_DATA         |
    |-------------------------------+--------------------------------------+------------+----------------------------------------------------------------------+--------------------|
    | 2026-03-12 12:18:39.470 -0700 | 01c2fc06-000e-6668-0000-76b90170a28e |     100038 | {                                                                    | {                  |
    |                               |                                      |            |   "error_code": 100038,                                              |   "N": [           |
    |                               |                                      |            |   "error_message": "Numeric value 'invalid_cast' is not recognized", |     "invalid_cast" |
    |                               |                                      |            |   "error_source": "N",                                               |   ],               |
    |                               |                                      |            |   "sql_state": "22018"                                               |   "T": "1"         |
    |                               |                                      |            | }                                                                    | }                  |
    | 2026-03-12 12:18:39.470 -0700 | 01c2fc06-000e-6668-0000-76b90170a28e |     100072 | {                                                                    | {                  |
    |                               |                                      |            |   "error_code": 100072,                                              |   "N": [           |
    |                               |                                      |            |   "error_message": "NULL result in a non-nullable column",           |     null           |
    |                               |                                      |            |   "error_source": "N",                                               |   ],               |
    |                               |                                      |            |   "sql_state": "22000"                                               |   "T": [           |
    |                               |                                      |            | }                                                                    |     "toolong"      |
    |                               |                                      |            |                                                                      |   ]                |
    |                               |                                      |            |                                                                      | }                  |
    +-------------------------------+--------------------------------------+------------+----------------------------------------------------------------------+--------------------+
    
  5. test_dml_error_logging 表关闭 DML 错误日志记录:

    ALTER TABLE test_dml_error_logging
      SET ERROR_LOGGING = false;
    
  6. 尝试您之前运行的相同 INSERT 语句。返回错误,并且错误表中不记录任何错误:

    INSERT INTO test_dml_error_logging
      VALUES
        ('invalid_cast', '1'),
        (10, 'valid'),
        (NULL, 'toolong');
    
    100038 (22018): DML operation to table TEST_DML_ERROR_LOGGING failed on column N with error: Numeric value 'invalid_cast' is not recognized
    

记录将一个表中的行插入另一个表中时出现的错误

以下示例记录了将一个表中的行插入另一个表中时出现的错误:

  1. 创建源表并插入值:

    CREATE TABLE dml_error_logging_source(col1 INT);
    
    INSERT INTO dml_error_logging_source VALUES (1), (0), (-1);
    
  2. 创建与源表具有相同定义的目标表:

    CREATE TABLE dml_error_logging_target(col1 INT);
    
  3. dml_error_logging_target 表开启 DML 错误日志记录:

    ALTER TABLE dml_error_logging_target
      SET ERROR_LOGGING = true;
    
  4. 通过查询源表将值插入到目标表中,使其中一次插入产生除以零的错误:

    INSERT INTO dml_error_logging_target(col1)
      SELECT 1/col1 FROM dml_error_logging_source;
    
    +-------------------------+
    | number of rows inserted |
    |-------------------------|
    |                       2 |
    +-------------------------+
    
  5. 查询表以确认插入了两个有效行:

    SELECT * FROM dml_error_logging_target;
    
    +------+
    | COL1 |
    |------|
    |    1 |
    |   -1 |
    +------+
    
  6. 查询 dml_error_logging_target 基表的错误表,以查看记录的错误:

    SELECT * FROM ERROR_TABLE(dml_error_logging_target);
    
    +-------------------------------+--------------------------------------+------------+----------------------------------------+-------------+
    | TIMESTAMP                     | QUERY_ID                             | ERROR_CODE | ERROR_METADATA                         | ERROR_DATA  |
    |-------------------------------+--------------------------------------+------------+----------------------------------------+-------------|
    | 2026-03-12 12:25:56.297 -0700 | 01c2fc0d-000e-6696-0000-76b90170b64a |     100051 | {                                      | {           |
    |                               |                                      |            |   "error_code": 100051,                |   "COL1": [ |
    |                               |                                      |            |   "error_message": "Division by zero", |     1,      |
    |                               |                                      |            |   "error_source": "COL1",              |     0       |
    |                               |                                      |            |   "sql_state": "22012"                 |   ]         |
    |                               |                                      |            | }                                      | }           |
    +-------------------------------+--------------------------------------+------------+----------------------------------------+-------------+
    

错误日志记录和错误表

为表开启错误日志记录时,Snowflake 会自动创建与基表关联的错误表。遇到受支持错误的 DML 操作会在错误表中记录错误,而不是失败。

为表开启 DML 错误日志记录后,将记录以下类型的 DML 语句:

  • 单个表 INSERT

  • UPDATE

  • MERGE

错误表具有固定的定义,只能由基表的所有者,或被授予基础表 SELECT ERROR TABLE 权限的角色访问。错误表唯一支持的直接操作是 SELECT 和 TRUNCATE 语句。不能直接对错误表运行其他类型的语句。错误表不能在物化视图或动态表中间接使用。

您可以将错误表中的数据复制到其他表中。您可以通过运行 TRUNCATE 命令来移除错误表中的数据。

以下部分提供了有关错误日志记录和错误表的更多信息:

错误表定义

Snowflake 使用无法修改的标准定义创建错误表。

当您为基表关闭 DML 错误日志记录或删除具有错误表的基表时,与该基表关联的错误表将自动删除。

错误表包含以下列:

名称

类型

描述

timestamp

TIMESTAMP

触发错误的语句的时间戳。

query_id

VARCHAR

触发错误的语句的唯一 ID。

error_code

NUMBER

错误代码。当一行中的多个列包含错误时,此列仅捕获遇到的第一个错误。

error_metadata

OBJECT

错误元数据。

OBJECT 值具有以下结构:

{
  "error_code": <value>,
  "error_message": "<value>",
  "error_source": "<value>",
  "sql_state": "<value>"
}

OBJECT 值包含以下键值对:

  • error_code:选择使用 时默认使用的角色和仓库。错误代码。

  • error_message:选择使用 时默认使用的角色和仓库。错误消息。

  • error_source:选择使用 时默认使用的角色和仓库。错误的来源,例如列名。

  • sql_state:选择使用 时默认使用的角色和仓库。基于 ANSI SQL 标准 SQLSTATE (link removed) 的 5 字符代码。除 ANSI SQL 标准中的值外,Snowflake 还使用了其他值。

当一行中的多个列包含错误时,此列仅捕获遇到的第一个错误。

error_data

OBJECT

导致错误的数据。

OBJECT 值具有以下结构:

{
  "<column_name>": [
    <invalid_column_values>
  ]
  "<column_name>": <valid_column_values>
  ...
}

OBJECT 值包含表示基表中每一列的键值对。键是列名称。对于导致 DML 操作失败的无效列值,键值对中的值是包含值的数组。直接显示有效值;即它们不显示在数组中。

如果数据无法以 OBJECT 值表示,该值为 NULL。

与错误表交互

您可以使用以下语法对错误表运行 SELECT 语句和 TRUNCATE 语句:

SELECT ... FROM ERROR_TABLE( <base_table_name> )

TRUNCATE [ TABLE ] [ IF EXISTS ] ERROR_TABLE( <base_table_name> )

其中:

base_table_name

为其创建错误表的表的名称。

例如,如果基表的名称是 my_table,以下语句查询此基表的错误表:

SELECT * FROM ERROR_TABLE(my_table);

以下语句截断错误表:

TRUNCATE ERROR_TABLE(my_table);

错误表的访问控制要求

任何能够向基表插入数据的角色,都可以触发向其错误表的插入操作。无论当前角色如何,都不允许直接插入错误表。

以下用户可以对错误表运行 SELECT 语句:

  • 错误表基表的所有者。

  • 通过角色或直接获得基表 SELECT ERROR TABLE 权限的用户。

    要授予基表的 SELECT ERROR TABLE 权限,请运行 GRANT <privileges> ... TO ROLE 语句或 GRANT <privileges> ... TO USER 语句。

    这些语句使用以下语法:

    GRANT SELECT ERROR TABLE ON TABLE <base_table_name> TO ROLE <role_name>
    
    GRANT SELECT ERROR TABLE ON TABLE <base_table_name> TO USER <user_name>
    

    例如,要将名为 mybasetable 的基表的 SELECT ERROR TABLE 权限授予名为 myrole 的角色,请运行以下语句:

    GRANT SELECT ERROR TABLE ON TABLE mybasetable TO ROLE myrole;
    

或者,要授予其他角色访问错误表的权限,基表所有者还可以基于错误表创建视图,并授予对该视图的访问权限。

错误日志记录的元数据

要确定是否为表开启了错误日志记录,可以运行 GET_DDL 函数并传入基表的名称:

SELECT GET_DDL('TABLE', '[<namespace>.]<base_table_name>');

例如,对于当前架构中名为 test_dml_error_logging 的基表,请运行以下语句:

SELECT GET_DDL('TABLE', 'test_dml_error_logging');
+--------------------------------------------------+
| GET_DDL('TABLE', 'TEST_DML_ERROR_LOGGING')       |
|--------------------------------------------------|
| create or replace TABLE TEST_DML_ERROR_LOGGING ( |
|     N NUMBER(4,0) NOT NULL,                      |
|     T VARCHAR(5)                                 |
| ) ERROR_LOGGING = true                           |
| ;                                                |
+--------------------------------------------------+

错误表的指标记录在以下视图中:

错误表的流

错误表不直接支持 。要对错误表启用变更跟踪,请先在错误表上创建视图,然后在视图上创建流。

以下示例展示了如何对错误表启用变更跟踪:

  1. 运行 CREATE VIEW 命令,在错误表上创建视图:

    CREATE VIEW my_error_view AS
      SELECT timestamp,
             query_id,
             error_code,
             error_metadata,
             error_data
        FROM ERROR_TABLE(test_dml_error_logging);
    
  2. 运行 CREATE STREAM 命令,在视图上创建流:

    CREATE STREAM my_error_stream ON VIEW my_error_view;
    

DML 错误日志记录使用说明

为表开启错误日志记录后,以下使用说明适用:

  • 仅记录与基表直接相关的错误。

  • 记录以下类型的错误:

    • NOT NULL 表约束条件违规。

    • 尝试将某个值转换到基表列时发生的类型转换错误。

    • 不兼容的精度和小数位数值。

    • 字符串和二进制类型的长度不兼容。

    • 某些表达式求值失败,例如除以零或 PARSE_JSON 函数执行失败。

  • 多表 INSERT 和 CREATE TABLE ... AS SELECT (CTAS) 语句正常运行。它们在遇到 DML 错误时会失败,并且不会记录这些错误。

  • 如果您尝试对启用了错误日志记录的表运行 COPY INTO 语句,则编译时会返回 Error logging is not supported in statement 'COPY INTO' 错误。

  • DML 错误日志记录不支持的错误会直接导致 DML 操作失败。

  • 如果 SQL 语句导致编译错误,则操作结束,错误表中不会记录任何错误。

  • 其他引入路径中的失败,例如 COPY、Snowpipe 和 Snowpipe Streaming 不会记录在错误表中。

  • 以下是 DML 错误日志记录和性能的相关注意事项:

    • 当为基表启用 DML 错误日志记录时,如果对基表执行的 DML 语句 没有 错误,预计性能不会有差异或差异很小。

    • 当为基表启用 DML 错误日志记录时,如果对基表执行的 DML 语句中 错误,完成该 DML 语句将需要额外时间,因为错误信息会被插入到错误表中。

  • 克隆具有关联错误表的基表时,行为如下:

    • 克隆基表的架构和内容。

    • 未克隆错误表的内容

    • 克隆的基表启用了 ERROR_LOGGING 属性,这会隐式为其创建一个空的错误表。

从暂存的半结构化数据文件中对列定义进行架构检测

半结构化数据可能包含数千列。Snowflake 为处理此类数据提供了强大的解决方案。选项包括使用外部表直接在云存储中引用数据、将数据加载到 VARIANT 类型的单个列中,或对数据进行转换并将其加载到标准关系表中的单独列中。所有这些选项都需要对数据中的列定义有一定了解。

另一种解决方案涉及到在一组暂存的半结构化数据文件中自动检测架构,并检索列定义。列定义包括文件中的列名称、列数据类型和列顺序。按照适合创建 Snowflake 标准表、外部表或视图的格式生成语法。

备注

此功能支持 Apache Parquet、Apache Avro、ORC、JSON 和 CSV 文件。

此支持通过以下 SQL 函数实现:

INFER_SCHEMA

检测一组暂存的数据文件中的列定义,并以适合创建 Snowflake 对象的格式检索元数据。

GENERATE_COLUMN_DESCRIPTION

使用 INFER_SCHEMA 函数输出,基于一组暂存文件生成列列表。

这些 SQL 函数支持内部和外部暂存区。

使用如下语法,通过基于一组暂存文件得出的列定义创建表或外部表: CREATE TABLE ...USING TEMPLATECREATE EXTERNAL TABLE ...USING TEMPLATE。USING TEMPLATE 子句接受一个表达式,该表达式调用 INFER_SCHEMA SQL 函数,检测文件中的列定义。创建表后,您可以使用带 MATCH_BY_COLUMN_NAME 选项的 COPY 语句,将文件直接加载到结构化表中。

架构检测也可以与 表模式演化 结合使用,其中,表的结构会自动演化,以支持从数据源接收的新数据的结构。

加载数据的替代方案

您可以使用以下选项查询云存储中的数据,而不需要将其加载到 Snowflake 表中。

External Tables(数据湖)

External Tables 支持查询存储在外部云存储中的现有数据,以便进行分析,而不需要先将其加载到 Snowflake 中。数据的事实来源仍保留在外部云存储中。通过物化视图在 Snowflake 中物化的数据集为只读。

这种解决方案特别适合在外部云存储中存储了大量数据,且只想查询部分数据(例如最新数据)的账户。用户可基于此数据的子集创建物化视图,以提高查询性能。

使用兼容 Amazon S3 的存储

您可以在 Snowflake 中创建外部暂存区和表,以访问与 Amazon S3 兼容的应用程序或设备中的存储。此功能可让您管理、治理和分析数据,而不考虑数据的存储位置。有关信息,请参阅 Work with Amazon S3-compatible storage