Apache Iceberg™ 테이블에 데이터 로드하기

Snowflake는 Snowflake가 관리하는 Iceberg 테이블에 데이터를 로딩할 때 다음과 같은 선택 사항을 지원합니다.

파일 형식

표준 Snowflake 테이블에 로드할 수 있도록 지원되는 형식의 파일에서 Iceberg 테이블로 데이터를 로드할 수 있습니다.

CSV, JSON, Avro 및 ORC 의 경우 Snowflake는 비 Parquet 파일 형식의 데이터를 Iceberg Parquet 파일로 변환하여 Iceberg 테이블의 기본 위치에 데이터를 저장합니다. 유형 변환이 필요한 이러한 파일 형식 로딩 시나리오에는 기본 LOAD_MODE = FULL_INGEST 옵션만 지원됩니다.

Apache Parquet 파일의 경우 Snowflake는 데이터를 테이블 열에 직접 로딩하고 다음 LOAD_MODE 옵션 중에서 선택할 수 있습니다.

  • FULL_INGEST: 파일을 스캔하고 Iceberg 테이블의 기본 위치 아래에 Parquet 데이터를 다시 작성합니다.

  • ADD_FILES_COPY: Binary는 Iceberg 카탈로그에 등록되지 않은 Iceberg 호환 Apache Parquet 파일을 Iceberg 테이블의 기본 위치에 복사한 다음, 파일을 Iceberg 테이블에 등록합니다.

자세한 내용은 COPY INTO <테이블> 섹션을 참조하십시오.

중요

ADD_FILES_COPY를 사용하여 Parquet 파일을 등록하는 작업은 해당 파일이 이미 다른 Iceberg 테이블의 일부인 경우 권장되지 않습니다.

파일을 다시 작성하지 않고 외부 관리 Iceberg 테이블을 Snowflake 관리 Iceberg 테이블로 변환하는 가장 좋은 방법은 ALTER ICEBERG TABLE … CONVERT TO MANAGED 명령을 사용하는 것입니다.

Iceberg 테이블에 데이터를 로드할 때의 고려 사항 및 제한 사항

  • Parquet 파일에 대한 행 계보 메타데이터 열(_row_id_last_updated_sequence_number)을 로드하려면 FULL_INGEST 옵션을 사용해야 합니다. 기타 LOAD_MODE 옵션은 지원되지 않습니다. 그러나 행 계보가 포함된 Parquet 파일은 이미 Iceberg v3 테이블의 일부일 수 있습니다. 이미 다른 Iceberg 테이블의 일부인 Parquet 파일을 처리하는 방법에 대한 모범 사례는 :ref:`위의 참고 사항 <label-tables_iceberg_load_mode>`을 참조하세요.

예제: Iceberg 호환 Parquet 파일 로드하기

이 예제에서는 Iceberg 테이블을 생성한 다음 외부 스테이지의 Iceberg 호환 Parquet 데이터 파일에서 데이터를 로딩하는 방법을 보여줍니다.

중요

ADD_FILES_COPY를 사용하여 Parquet 파일을 등록하는 작업은 해당 파일이 이미 다른 Iceberg 테이블의 일부인 경우 권장되지 않습니다. 파일을 다시 작성하지 않고 외부 관리 Iceberg 테이블을 Snowflake 관리 Iceberg 테이블로 변환하는 가장 좋은 방법은 ALTER ICEBERG TABLE … CONVERT TO MANAGED 명령을 사용하는 것입니다.

데모 목적으로 이 예제에서는 다음 리소스를 사용합니다.

  • iceberg_ingest_vol 이라는 외부 볼륨. 외부 볼륨을 생성하려면 외부 볼륨 구성 섹션을 참조하십시오.

  • my_parquet_stage 라는 외부 스테이지에 Iceberg와 호환되는 Parquet 파일이 있습니다. 외부 스테이지를 생성하려면 CREATE STAGE 섹션을 참조하십시오.

  1. Iceberg 호환 Parquet 데이터(TYPE = PARQUET USE_VECTORIZED_SCANNER = TRUE)를 복사하는 데 필요한 구성을 사용하여 스테이징된 Parquet 파일을 설명하는 파일 형식 오브젝트를 만듭니다.

    CREATE OR REPLACE FILE FORMAT my_parquet_format
      TYPE = PARQUET
      USE_VECTORIZED_SCANNER = TRUE;
    
    Copy
  2. 원본 Parquet 파일 데이터 타입과 호환되는 데이터 타입으로 열을 정의하여 Snowflake 관리형 Iceberg 테이블을 만듭니다.

    이 예제에서는 대/소문자를 구분하는 열 이름을 사용합니다. Iceberg 테이블을 생성할 때 열 이름을 큰따옴표로 묶어야 하며 Parquet 바닥글에 표시되는 열 이름을 정확히 지정해야 합니다.

    CREATE OR REPLACE ICEBERG TABLE customer_iceberg_ingest (
      "c_custkey" INTEGER,
      "c_name" STRING,
      "c_address" STRING,
      "c_nationkey" INTEGER,
      "c_phone" STRING,
      "c_acctbal" INTEGER,
      "c_mktsegment" STRING,
      "c_comment" STRING
    )
      CATALOG = 'SNOWFLAKE'
      EXTERNAL_VOLUME = 'iceberg_ingest_vol'
      BASE_LOCATION = 'customer_iceberg_ingest/';
    
    Copy

    참고

    예제 문은 Snowflake 데이터 타입에 매핑되는 Iceberg 데이터 타입을 지정합니다. 자세한 내용은 Apache Iceberg™ 테이블의 데이터 타입 섹션을 참조하십시오.

  3. 스테이징된 Parquet 파일(스테이지 URL 경로 바로 아래에 위치)의 데이터를 Iceberg 테이블로 로드하려면 COPY INTO 문을 사용합니다.

    :code:`LOAD_MODE = ADD_FILES_COPY`를 사용한 COPYINTO*<table>* 문에서는 :code:`MATCH_BY_COLUMN_NAME = CASE_SENSITIVE`만 지원됩니다.

    COPY INTO customer_iceberg_ingest
      FROM @my_parquet_stage
      FILE_FORMAT = 'my_parquet_format'
      LOAD_MODE = ADD_FILES_COPY
      PURGE = TRUE
      MATCH_BY_COLUMN_NAME = CASE_SENSITIVE;
    
    Copy

    참고

    이 예제에서는 LOAD_MODE = ADD_FILES_COPY 를 지정하여 Snowflake가 파일을 외부 볼륨 위치에 복사본으로 복사한 다음 파일을 테이블에 등록하도록 지시합니다.

    이 선택 사항은 원본 Parquet 파일을 스캔하여 데이터를 새 Parquet 파일로 다시 작성하지 않으므로 파일 요금을 피할 수 있습니다.

    출력:

    +---------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
    | file                                                          | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name |
    |---------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------|
    | my_parquet_stage/snow_af9mR2HShTY_AABspxOVwhc_0_1_008.parquet | LOADED |       15000 |       15000 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    | my_parquet_stage/snow_af9mR2HShTY_AABspxOVwhc_0_1_006.parquet | LOADED |       15000 |       15000 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    | my_parquet_stage/snow_af9mR2HShTY_AABspxOVwhc_0_1_005.parquet | LOADED |       15000 |       15000 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    | my_parquet_stage/snow_af9mR2HShTY_AABspxOVwhc_0_1_002.parquet | LOADED |           5 |           5 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    | my_parquet_stage/snow_af9mR2HShTY_AABspxOVwhc_0_1_010.parquet | LOADED |       15000 |       15000 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    +---------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
    
  4. 테이블을 쿼리합니다.

    SELECT
        c_custkey,
        c_name,
        c_mktsegment
      FROM customer_iceberg_ingest
      LIMIT 10;
    
    Copy

    출력:

    +-----------+--------------------+--------------+
    | C_CUSTKEY | C_NAME             | C_MKTSEGMENT |
    |-----------+--------------------+--------------|
    |     75001 | Customer#000075001 | FURNITURE    |
    |     75002 | Customer#000075002 | FURNITURE    |
    |     75003 | Customer#000075003 | MACHINERY    |
    |     75004 | Customer#000075004 | AUTOMOBILE   |
    |     75005 | Customer#000075005 | FURNITURE    |
    |         1 | Customer#000000001 | BUILDING     |
    |         2 | Customer#000000002 | AUTOMOBILE   |
    |         3 | Customer#000000003 | AUTOMOBILE   |
    |         4 | Customer#000000004 | MACHINERY    |
    |         5 | Customer#000000005 | HOUSEHOLD    |
    +-----------+--------------------+--------------+
    

예시: INFER_SCHEMA 함수를 사용하여 생성한 테이블에 Iceberg 호환 Parquet 파일 로딩하기

이 예제에서는 다음을 수행하는 방법을 다룹니다.

  1. INFER_SCHEMA 함수를 사용하여 Apache Iceberg™ 테이블을 생성합니다.

  2. 외부 스테이지에 있는 Iceberg 호환 Parquet 데이터 파일에서 데이터를 로딩합니다.

데모 목적으로 이 예제에서는 다음 리소스를 사용합니다.

  • iceberg_ingest_vol 이라는 외부 볼륨. 외부 볼륨을 생성하려면 외부 볼륨 구성 섹션을 참조하십시오.

  • my_parquet_stage 라는 외부 스테이지에 Iceberg와 호환되는 Parquet 파일이 있습니다. 외부 스테이지를 생성하려면 CREATE STAGE 섹션을 참조하십시오.

  1. Iceberg 호환 Parquet 데이터(TYPE = PARQUET USE_VECTORIZED_SCANNER = TRUE)를 복사하는 데 필요한 구성을 사용하여 스테이징된 Parquet 파일을 설명하는 파일 형식 오브젝트를 만듭니다.

    CREATE OR REPLACE FILE FORMAT my_parquet_format
      TYPE = PARQUET
      USE_VECTORIZED_SCANNER = TRUE;
    
    Copy
  2. my_parquet_stage 스테이지에서 Parquet 파일에 대한 열 정의를 검색합니다.

    SELECT *
      FROM TABLE(
        INFER_SCHEMA(
          LOCATION=>'@my_parquet_stage/customer_iceberg/files-to-ingest/'
          , FILE_FORMAT=>'my_parquet_format'
          , KIND => 'ICEBERG'
          )
        );
    
    Copy

    출력:

    +-------------+---------+----------+---------------------+------------------------------------------------------+----------+
    | COLUMN_NAME | TYPE    | NULLABLE | EXPRESSION          | FILENAMES                                            | ORDER_ID |
    |-------------+---------+----------+---------------------+------------------------------------------------------|----------+
    | id          | INT     | False    | $1:id::INT          | customer_iceberg/files-to-ingest/customers.parquet   | 0        |
    | custnum     | INT     | False    | $1:custnum::INT     | customer_iceberg/files-to-ingest/customers.parquet   | 1        |
    +-------------+---------+----------+---------------------+------------------------------------------------------+----------+
    
  3. 감지된 스키마를 사용하여 Iceberg 테이블을 생성합니다.

    CREATE ICEBERG TABLE myicebergtable
      USING TEMPLATE (
        SELECT ARRAY_AGG(OBJECT_CONSTRUCT(*))
        WITHIN GROUP (ORDER BY order_id)
          FROM TABLE(
            INFER_SCHEMA(
              LOCATION=>'@my_parquet_stage/customer_iceberg/files-to-ingest/',
              FILE_FORMAT=>'my_parquet_format',
              KIND => 'ICEBERG'
            )
          ))
     ... {rest of the ICEBERG options}
     ;
    
    Copy

    참고

    ARRAY_AGG(OBJECT_CONSTRUCT()) 에 대해 * 를 사용하면 반환된 결과가 16MB 보다 클 경우 오류가 발생할 수 있습니다. 큰 결과 세트에는 * 를 사용하지 말고 쿼리에는 필수 열인 COLUMN NAME, TYPE, NULLABLE 만 사용하는 것이 좋습니다. WITHIN GROUP (ORDER BY order_id) 를 사용할 때 선택적 열 ORDER_ID 를 포함할 수 있습니다.

  4. COPY INTO 문을 사용하여 스테이징된 Parquet 파일의 데이터를 Iceberg 테이블로 로딩합니다.

    COPY INTO myicebergtable
      FROM @my_parquet_stage/customer_iceberg/files-to-ingest/
      FILE_FORMAT = 'my_parquet_format'
      LOAD_MODE = ADD_FILES_COPY
      MATCH_BY_COLUMN_NAME = CASE_SENSITIVE;
    
    Copy

    참고

    이 예제에서는 LOAD_MODE = ADD_FILES_COPY 를 지정하여 Snowflake가 파일을 외부 볼륨 위치에 복사본으로 복사한 다음 파일을 테이블에 등록하도록 지시합니다.

    이 선택 사항은 원본 Parquet 파일을 스캔하여 데이터를 새 Parquet 파일로 다시 작성하지 않으므로 파일 요금을 피할 수 있습니다.

    출력:

    +---------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
    | file                                                                | status | rows_parsed | rows_loaded | error_limit | errors_seen | first_error | first_error_line | first_error_character | first_error_column_name |
    |---------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------|
    | my_parquet_stage/customer_iceberg/files-to-ingest/customers.parquet | LOADED |       15000 |       15000 |           0 |           0 | NULL        |             NULL |                  NULL | NULL                    |
    +---------------------------------------------------------------------+--------+-------------+-------------+-------------+-------------+-------------+------------------+-----------------------+-------------------------+
    
  5. 데이터 로딩 후 테이블을 쿼리합니다.

    SELECT
        id,
        custnum
      FROM myicebergtable
      LIMIT 10;
    
    Copy

    출력:

    +-----------+---------+
    | id        | custnum |
    |-----------+---------+
    |         1 |   75001 |
    |         2 |   75002 |
    |         3 |   75003 |
    |         4 |   75004 |
    |         5 |   75005 |
    |         6 |   75006 |
    |         7 |   75007 |
    |         8 |   75008 |
    |         9 |   75009 |
    |        10 |   75010 |
    +-----------+---------+