テーブルスキーマの進化

半構造化データは、時間の経過とともに進化する傾向があります。データを生成するシステムは、追加された情報に対応するために新しい列を追加し、それに応じて下流のテーブルを進化させる必要があります。

Snowflakeのテーブルの構造は、データソースから受け取った新しいデータの構造をサポートするために、自動的に進化させることができます。Snowflakeは、次をサポートしています。

  • 新しい列の自動追加。

  • 新しいデータファイルで欠落している列からの NOT NULL 制約の自動削除。

テーブルスキーマの進化を有効にするには、次を実行します。

  • 新しいテーブルを作成する場合は、 CREATE TABLE コマンドを使用する際に、 ENABLE_SCHEMA_EVOLUTION パラメーターを TRUE に設定します。

  • 既存のテーブルの場合は、 ALTER TABLE コマンドを使用してテーブルを変更し、 ENABLE_SCHEMA_EVOLUTION パラメーターを TRUE に設定します。

ファイルからのデータのロードでテーブル列が進化するのは、次のすべてが当てはまる場合です。

  • COPY INTO <テーブル> ステートメントには MATCH_BY_COLUMN_NAME オプションが含まれる。

  • データのロードに使用されるロールは、テーブルに対する EVOLVE SCHEMA または OWNERSHIP の権限を持っている。

さらに、 CSV でスキーマを進化させる際に、 MATCH_BY_COLUMN_NAMEPARSE_HEADER を使用する場合は、 ERROR_ON_COLUMN_COUNT_MISMATCH をfalseに設定する必要があります。

スキーマの進化は独立した機能ですが、クラウドストレージにある一連のファイルから 列定義を取得するためのサポート と組み合わせて使用できます。これらの機能を組み合わせると、クラウドストレージにある一連のデータファイルから新しいテーブルを作成し、列が追加または削除されて新しいソースデータファイルのスキーマが進化するとテーブルの列を変更する、連続データパイプラインを実現します。

使用上の注意

  • この機能は、Apache Avro、Apache Parquet、 CSV、 JSON、 ORC ファイルをサポートしています。

  • この機能は、 COPY INTO <テーブル> ステートメントとSnowpipeデータロードに限定されます。INSERT の操作で自動的にターゲットテーブルのスキーマを進化させることはできません。

  • Snowpipe Streaming のデータロードは、スキーマの進化をサポートしていません。

  • デフォルトでは、この機能は、 COPY の操作ごとに、最大10列の追加または1スキーマ以上の進化に制限されています。COPY の操作ごとに、10列を超える追加列または1つのスキーマをリクエストする場合は、 Snowflakeサポート にお問い合わせください。

  • NOT NULL 列制約のドロップには制限はありません。

次の例では、Parquetデータのセットから派生した列定義を持つテーブルを作成します。テーブルのスキーマの自動進化を有効にすると、名前と値のペアを追加したParquetファイルからさらにデータを読み取る際に、列がテーブルに自動で追加されます。

ステートメントで参照されている mystage ステージと my_parquet_format ファイル形式がすでに存在している必要があることに注意してください。ファイルのセットは、ステージ定義で参照されるクラウドストレージの場所に既にステージングされている必要があります。

この例は、 INFER_SCHEMA トピックの例に基づいて構築されています。

-- Create table t1 in schema d1.s1, with the column definitions derived from the staged file1.parquet file.
USE SCHEMA d1.s1;

CREATE OR REPLACE TABLE t1
  USING TEMPLATE (
    SELECT ARRAY_AGG(object_construct(*))
      FROM TABLE(
        INFER_SCHEMA(
          LOCATION=>'@mystage/file1.parquet',
          FILE_FORMAT=>'my_parquet_format'
        )
      ));

-- Row data in file1.parquet.
+------+------+------+
| COL1 | COL2 | COL3 |
|------+------+------|
| a    | b    | c    |
+------+------+------+

-- Describe the table.
-- Note that column c2 is required in the Parquet file metadata. Therefore, the NOT NULL constraint is set for the column.
DESCRIBE TABLE t1;
+------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+
| name | type              | kind   | null? | default | primary key | unique key | check | expression | comment | policy name |
|------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------|
| COL1 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
| COL2 | VARCHAR(16777216) | COLUMN | N     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
| COL3 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
+------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+

-- Use the SECURITYADMIN role or another role that has the global MANAGE GRANTS privilege.
-- Grant the EVOLVE SCHEMA privilege to any other roles that could insert data and evolve table schema in addition to the table owner.

GRANT EVOLVE SCHEMA ON TABLE d1.s1.t1 TO ROLE r1;

-- Enable schema evolution on the table.
-- Note that the ENABLE_SCHEMA_EVOLUTION property can also be set at table creation with CREATE OR REPLACE TABLE
ALTER TABLE t1 SET ENABLE_SCHEMA_EVOLUTION = TRUE;

-- Load a new set of data into the table.
-- The new data drops the NOT NULL constraint on the col2 column.
-- The new data adds the new column col4.
COPY INTO t1
  FROM @mystage/file2.parquet
  FILE_FORMAT = (type=parquet)
  MATCH_BY_COLUMN_NAME = CASE_INSENSITIVE;

-- Row data in file2.parquet.
+------+------+------+
| col1 | COL3 | COL4 |
|------+------+------|
| d    | e    | f    |
+------+------+------+

-- Describe the table.
DESCRIBE TABLE t1;
+------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+
| name | type              | kind   | null? | default | primary key | unique key | check | expression | comment | policy name |
|------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------|
| COL1 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
| COL2 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
| COL3 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
| COL4 | VARCHAR(16777216) | COLUMN | Y     | NULL    | N           | N          | NULL  | NULL       | NULL    | NULL        |
+------+-------------------+--------+-------+---------+-------------+------------+-------+------------+---------+-------------+
-- Note that since MATCH_BY_COLUMN_NAME is set as CASE_INSENSITIVE, all column names are retrieved as uppercase letters.
Copy