データファイルの準備

このトピックでは、データファイルをロード用に準備するためのベストプラクティス、一般的なガイドライン、および重要な考慮事項について説明します。

このトピックの内容:

ファイルサイズのベストプラクティス

最適なロードパフォーマンスと サイズ制限 を回避するために、次のデータファイルのサイズ設定ガイドラインを考慮します。これらの推奨事項は、Snowpipeを使用した連続ロードだけでなく、一括データロードにも該当します。

一般的なファイルサイズの推奨事項

並行して実行されるロード操作の数は、ロードされるデータファイルの数を超えることはできません。ロードの並列操作の数を最適化するには、 圧縮された データファイルのサイズをおよそ100から250 MB(またはそれ以上)にすることをお勧めします。

注釈

非常に大きなファイル(例: 100 GB 以上)をロードすることはお勧めしません。

大きなファイルをロードする必要がある場合は、 ON_ERROR コピーオプションの値を慎重に検討してください。少数のエラーでファイルを中止またはスキップすると、遅延が発生し、クレジットが無駄になる可能性があります。さらに、データのロード操作が最大許容時間の24時間を超えて継続した場合は、ファイルの一部がコミットされずに中止される可能性があります。

小さいファイルを集約して、各ファイルの処理オーバーヘッドを最小限に抑えます。アクティブなウェアハウス内のコンピューティングリソース間でロードを分散するために、大きなファイルを多数の小さなファイルに分割します。並行して処理されるデータファイルの数は、ウェアハウス内のコンピューティングリソースの量によって決まります。記録がチャンクにまたがることを避けるために、大きなファイルは行で分割することをお勧めします。

データソースがデータファイルを小さなチャンクでエクスポートできない場合は、サードパーティのユーティリティを使用して大容量ファイル (CSV) を分割することができます。

RFC4180 仕様に従った大容量の非圧縮 CSV ファイル(128MB を超える)をロードする場合、 MULTI_LINE を FALSE に、 COMPRESSION を NONE に設定し、 ` and ON_ERROR is set to `` ABORT_STATEMENT `` or `` CONTINUE`` に設定すると、Snowflakeはこれらの CSV ファイルの並列スキャンをサポートします。

Linuxまたは macOS

split ユーティリティを使用すると、 CSV ファイルを複数の小さなファイルに分割できます。

構文:

split [-a suffix_length] [-b byte_count[k|m]] [-l line_count] [-p pattern] [file [name]]
Copy

詳細については、ターミナルウィンドウに man split と入力します。

例:

split -l 100000 pagecounts-20151201.csv pages
Copy

この例では、 pagecounts-20151201.csv という名前のファイルを行の長さで分割します。8 GB の大きな単一ファイルに、10百万行が含まれているとします。100,000で分割すると、100個の小さいファイルのそれぞれは80 MB (10百万/100,000 = 100)です。分割ファイルの名前は pagessuffix です。

Windows

Windowsには、ネイティブファイル分割ユーティリティは含まれていません。ただしWindowsは、大きなデータファイルを分割できる多くのサードパーティツールとスクリプトをサポートしています。

データベースオブジェクトのサイズ制限

注釈

このセクションで説明するサイズ制限を使用するには、 2025_03 動作変更バンドル をアカウントで有効にする必要があります。このバンドルはデフォルトでは無効になっています。

2025_03 動作変更バンドルが無効な場合、 VARCHAR 、 VARIANT 、 ARRAY 、 OBJECT タイプの列の最大許容長さは 16 MB であり、 BINARY 、 GEOGRAPHY 、 GEOMETRY タイプの列の最大許容長さは 8 MB です。

アカウントでバンドルを有効にするには、次のステートメントを実行します。

SELECT SYSTEM$ENABLE_BEHAVIOR_CHANGE_BUNDLE('2025_03');
Copy

詳細については、 データベースオブジェクトの新しい最大サイズ制限(保留中) をご参照ください。

Snowflake にデータ読み込み中 の利用可能メソッドを使用すると、16 MB を超えるサイズのオブジェクトを列に格納できるようになりました。特定のデータタイプには以下の制限が適用されます。

データ型

ストレージ制限

ARRAY

128 MB

BINARY

64 MB

GEOGRAPHY

64 MB

GEOMETRY

64 MB

OBJECT

128 MB

VARCHAR

128 MB

VARIANT

128 MB

VARCHAR 列のデフォルトサイズは16 MB のままです (バイナリの場合は8 MB)。16 MB を超える列を持つテーブルを作成する場合は、明示的にサイズを指定します。例:

CREATE OR REPLACE TABLE my_table (
  c1 VARCHAR(134217728),
  c2 BINARY(67108864));
Copy

VARCHAR 列の新しい制限を使用するには、列のサイズを変更するためにテーブルを変更することができます。例:

ALTER TABLE my_table ALTER COLUMN col1 SET DATA TYPE VARCHAR(134217728);
Copy

これらのテーブルのBINARYタイプの列に新しいサイズを適用するには、テーブルを再作成してください。既存のテーブルのBINARY列の長さを変更することはできません。

ARRAY 、 GEOGRAPHY 、 GEOMETRY 、 OBJECT 、 VARIANT のタイプの列については、デフォルトでは、既存のテーブルや新しいテーブルに、長さを指定せずに、16 MB より大きなオブジェクトを格納することができます。例:

CREATE OR REPLACE TABLE my_table (c1 VARIANT);
Copy

これらの変更はUnistoreのワークロードには影響しません。ハイブリッド・テーブルの場合、現在の制限はすべて変更されません。

新しいサイズ制限が導入される前に作成された、 VARIANT 、 VARCHAR 、 BINARY の値を入力または出力として使用するプロシージャや関数も、16 MB より大きなオブジェクトをサポートするように(長さを指定せずに)再作成する必要があります。例:

CREATE OR REPLACE FUNCTION udf_varchar(g1 VARCHAR)
  RETURNS VARCHAR
  AS $$
    'Hello' || g1
  $$;
Copy

管理されていない Iceberg テーブル の場合、 VARCHAR および BINARY 列のデフォルトの長さは 128 MB です。このデフォルトの長さは、新しく作成または更新されたテーブルに適用されます。新しいサイズ制限が有効になる前に作成され、リフレッシュされなかったテーブルは、以前のデフォルトの長さのままです。

管理されているIcebergテーブルでは、VARCHARとBINARY列のデフォルトの長さは128 MBです。新しいサイズ制限が有効になる前に作成されたテーブルは、以前のデフォルトの長さのままです。これらのテーブルのVARCHARタイプの列に新しいサイズを適用するには、テーブルを再作成するか、列を変更してください。以下の例では、列を変更して新しいサイズ制限を使用しています。

ALTER ICEBERG TABLE my_iceberg_table ALTER COLUMN col1 SET DATA TYPE VARCHAR(134217728);
Copy

これらのテーブルのBINARYタイプの列に新しいサイズを適用するには、テーブルを再作成してください。既存のテーブルのBINARY列の長さを変更することはできません。

結果セットの大容量オブジェクトをサポートするドライバーバージョン

ドライバーは、16 MB (BINARY, GEOMETRY, GEOGRAPHY の場合は 8 MB) より大きなオブジェクトをサポートします。より大きなオブジェクトをサポートするバージョンにドライバーをアップデートする必要があるかもしれません。以下のドライバーバージョンが必要です。

ドライバー

バージョン

リリース日

Python用Snowparkライブラリ

1.21.0(またはそれ以上)

2024年8月19日

Snowflake Connector for Python

3.10.0(またはそれ以上)

2024年4月29日

JDBC

3.17.0(またはそれ以上)

2024年7月8日

ODBC

3.6.0(またはそれ以上)

2025年3月17日

Go Snowflakeドライバー

1.1.5(またはそれ以上)

2022年4月17日

.NET

2.0.11(またはそれ以上)

2022年3月15日

ScalaおよびJava用Snowparkライブラリ

1.14.0(またはそれ以上)

2024年9月14日

Node.js

1.6.9(またはそれ以上)

2022年4月21日

Sparkコネクタ

3.0.0(またはそれ以上)

2024年7月31日

PHP

3.0.2(またはそれ以上)

2024年8月29日

SnowSQL

1.3.2(またはそれ以上)

2024年8月12日

より大きなオブジェクトをサポートしていないドライバーを使用しようとすると、以下のようなエラーが返されます:

100067 (54000): The data length in result column <column_name> is not supported by this version of the client.
Actual length <actual_size> exceeds supported length of 16777216.

ロード前に16 MB より大きいオブジェクトのサイズを縮小する

2025_03 動作変更バンドルが無効になっている場合、データ型の制限を超えるサイズのオブジェクトをステージ上のファイルから以下のタイプの列のいずれかにロードしようとすると、エラーが発生します:

列に格納されるオブジェクトの最大サイズが16 MB であるため、以下のエラーが発生します:

Max LOB size (16777216) exceeded

過去には、このエラーは、 ステージ上のファイルをクエリ しようとした場合にも発生し、ファイルには16 MB より大きなオブジェクトが含まれていました。

列に16 MB 以上のオブジェクトを格納することはまだできませんが、ステージ上のファイルに128 MB までのオブジェクトをクエリできるようになりました。そして、列にオブジェクトを格納する前に、オブジェクトのサイズを小さくすることができます。16 MB より大きく128 MB より小さいオブジェクトを含むファイルをクエリしても、エラーが発生しなくなりました。

たとえば、大きなオブジェクトを複数の列や行に分割したり、ネストした JSON を表形式に変換したり、複雑な形状を単純化したりできます。

例: 大きな JSON ファイルを分割してロードする

一般に、 JSON データセットは、複数のドキュメントの単純な連結です。一部のソフトウェアからの JSON 出力は、複数の記録を含む単一の巨大な配列で構成されています。両方ともサポートされていますが、ドキュメントを改行またはコンマで区切る必要はありません。

データが 16 MB を超える場合は、 COPY INTO <テーブル> コマンドの STRIP_OUTER_ARRAY ファイル形式オプションを有効にして、外部配列構造を削除し、記録を別のテーブル行にロードします。

COPY INTO <table>
  FROM @~/<file>.json
  FILE_FORMAT = (TYPE = 'JSON' STRIP_OUTER_ARRAY = true);
Copy

例: Parquetファイルからの JSON オブジェクトのロードと分割

ステージからParquetファイルをロードしているとき、Parquetファイルに16 MB 以上のサイズの JSON オブジェクトが含まれていたとします:

{
  "ID": 1,
  "CustomerDetails": {
    "RegistrationDate": 158415500,
    "FirstName": "John",
    "LastName": "Doe",
    "Events": [
      {
        "Type": "LOGIN",
        "Time": 1584158401,
        "EventID": "NZ0000000001"
      },
      /* ... */
      /* this array contains thousands of elements */
      /* with total size exceeding 16 MB */
      /* ... */
      {
        "Type": "LOGOUT",
        "Time": 1584158402,
        "EventID": "NZ0000000002"
      }
    ]
  }
}
Copy

次の例では、ファイルのデータを格納するテーブルを作成し、そのテーブルにデータをロードしています。イベント配列のサイズが16 MB を超えることがあるため、この例では、イベント配列を別々の行(各配列要素に1つずつ)に展開しています。

CREATE OR REPLACE TABLE mytable AS
  SELECT
    t1.$1:ID AS id,
    t1.$1:CustomerDetails:RegistrationDate::VARCHAR AS RegistrationDate,
    t1.$1:CustomerDetails:FirstName::VARCHAR AS First_Name,
    t1.$1:CustomerDetails:LastName::VARCHAR AS as Last_Name,
    t2.value AS Event
  FROM @json t1,
    TABLE(FLATTEN(INPUT => $1:CustomerDetails:Events)) t2;
Copy

以下は、出来上がったテーブルの内容の例です。

+----+-------------------+------------+------------+------------------------------+
| ID | REGISTRATION_DATE | FIRST_NAME | LAST_NAME  | EVENT                        |
|----+-------------------+------------+------------+------------------------------|
| 1  | 158415500         | John       | Doe        | {                            |
|    |                   |            |            |   "EventID": "NZ0000000001", |
|    |                   |            |            |   "Time": 1584158401,        |
|    |                   |            |            |   "Type": "LOGIN"            |
|    |                   |            |            | }                            |
|                     ... thousands of rows ...                                   |
| 1  | 158415500         | John       | Doe        | {                            |
|    |                   |            |            |   "EventID": "NZ0000000002", |
|    |                   |            |            |   "Time": 1584158402,        |
|    |                   |            |            |   "Type": "LOGOUT"           |
|    |                   |            |            | }                            |
+----+-------------------+------------+------------+------------------------------+

FLATTEN の結果を既存のテーブルに挿入する

FLATTEN 関数の結果を既存のテーブルに挿入するには、 INSERT ステートメントを使用します。例:

CREATE OR REPLACE TABLE mytable (
  id VARCHAR,
  registration_date VARCHAR(16777216),
  first_name VARCHAR(16777216),
  last_name VARCHAR(16777216),
  event VARCHAR(16777216));

INSERT INTO mytable
  SELECT
    t1.$1:ID,
    t1.$1:CustomerDetails:RegistrationDate::VARCHAR,
    t1.$1:CustomerDetails:FirstName::VARCHAR,
    t1.$1:CustomerDetails:LastName::VARCHAR,
    t2.value
  FROM @json t1,
    TABLE(FLATTEN(INPUT => $1:CustomerDetails:Events)) t2;
Copy

例: XML のロードと分割

ステージから XML ファイルをロードしているとき、 XML オブジェクトが含まれていて、それが16 MB より大きいとします:

<?xml version='1.0' encoding='UTF-8'?>
<osm version="0.6" generator="osmium/1.14.0">
  <node id="197798" version="17" timestamp="2021-09-06T17:01:27Z" />
  <node id="197824" version="7" timestamp="2021-08-04T23:17:18Z" >
    <tag k="highway" v="traffic_signals"/>
  </node>
  <!--  thousands of node elements with total size exceeding 16 MB -->
  <node id="197826" version="4" timestamp="2021-08-04T16:43:28Z" />
</osm>
Copy

次の例では、ファイルのデータを格納するテーブルを作成し、そのテーブルにデータをロードしています。XML のサイズが16 MB を超えることがあるため、この例では各 node を別々の行に展開しています。

CREATE OR REPLACE TABLE mytable AS
  SELECT
    value:"@id" AS id,
    value:"@version" AS version,
    value:"@timestamp"::datetime AS TIMESTAMP,
    value:"$" AS tags
  FROM @mystage,
    LATERAL FLATTEN(INPUT => $1:"$")
  WHERE value:"@" = 'node';
Copy

以下は、出来上がったテーブルの内容の例です。

+--------+---------+-------------------------+---------------------------------------------+
| ID     | VERSION | TIMESTAMP               | TAGS                                        |
|--------+---------+-------------------------+---------------------------------------------|
| 197798 | 17      | 2021-09-06 17:01:27.000 | ""                                          |
| 197824 | 7       | 2021-08-04 23:17:18.000 | <tag k="highway" v="traffic_signals"></tag> |
|                   ... thousands of rows ...                                              |
| 197826 | 4       | 2021-08-04 16:43:28.000 | ""                                          |
+--------+---------+-------------------------+---------------------------------------------+

例: 大きな地理空間オブジェクトを保存する前にロードして簡素化する

ステージからParquetファイルをロードしているとき、そのParquetファイルに16 MB を超える地理空間オブジェクトが含まれていたとします。オブジェクトを保存する前に、ステージからファイルをロードし、(ST_SIMPLIFY を使用して)地理空間オブジェクトを簡略化することができます:

CREATE OR REPLACE TABLE mytable AS
  SELECT
    ST_SIMPLIFY($1:geo, 10) AS geo
  FROM @mystage;
Copy

例: COPY INTO <テーブル>の使用

COPY INTO <テーブル> を使用してステージ上のファイルからデータをロードする必要がある場合、 FLATTEN を使用して大きなオブジェクトを分割することはできません。代わりに、 SELECT を使用してください。例:

CREATE OR REPLACE TABLE mytable (
  id VARCHAR,
  registration_date VARCHAR,
  first_name VARCHAR,
  last_name VARCHAR);

COPY INTO mytable (
  id,
  registration_date,
  first_name,
  last_name
) FROM (
    SELECT
      $1:ID,
      $1:CustomerDetails::OBJECT:RegistrationDate::VARCHAR,
      $1:CustomerDetails::OBJECT:FirstName::VARCHAR,
      $1:CustomerDetails::OBJECT:LastName::VARCHAR
    FROM @mystage
);
Copy

連続データロード(Snowpipeなど)とファイルサイズ

Snowpipeは、通常、ファイル通知が送信されてから1分以内に新しいデータをロードするように設計されています。ただし、非常に大きなファイルの場合や、新しいデータの圧縮解除、復号化、変換に通常以上のコンピューティングリソースが必要な場合は、ロードにかなりの時間がかかることがあります。

リソースの消費に加えて、内部ロードキュー内のファイルを管理するためのオーバーヘッドも、Snowpipeに請求される使用コストに含まれます。このオーバーヘッドは、ロードのためにキューに入れられたファイルの数に連動して増加します。Snowpipeは外部テーブルの自動更新のイベント通知に使用されるため、このオーバーヘッド料金は請求明細書にSnowpipe料金として表示されます。

Snowpipeで最も効率的かつコスト効率の良い負荷を体験するためには、 ファイルサイズのベストプラクティス (このトピック内)の推奨ファイルサイジングに従うことをお勧めします。およそ100から250 MB 以上のデータファイルをロードすると、ロードされるデータの合計量に比べて、オーバーヘッドコストが重要ではなくなるまでオーバーヘッド料金が削減されます。

ソースアプリケーションに MBs のデータを蓄積するのに1分以上かかる場合は、新しい(潜在的に小さい)データファイルを1分に1回作成することを検討します。通常、このアプローチは、コスト(つまり、Snowpipeキュー管理に費やされるリソースと実際のロード)とパフォーマンス(つまり、ロードレイテンシー)のバランスにつながります。

小さなデータファイルを作成し、1分に1回よりも頻繁にクラウドストレージにステージングすることには、次の欠点があります。

  • データのステージングとロードの間のレイテンシーの縮小は保証できません。

  • 内部ロードキュー内のファイルを管理するためのオーバーヘッドは、Snowpipeに請求される使用コストに含まれています。このオーバーヘッドは、ロードのためにキューに入れられたファイルの数に連動して増加します。

さまざまなツールでデータファイルを集約およびバッチ処理できます。便利なオプションの1つは、Amazon Data Firehoseです。Firehoseでは、 バッファーサイズ と呼ばれる目的のファイルサイズと、 バッファーインターバル と呼ばれる新しいファイルが(この場合はクラウドストレージに)送信されるまでの待機間隔の両方を定義できます。詳細については、 Amazon Data Firehoseドキュメント をご参照ください。通常、ソースアプリケーションが1分以内に十分なデータを蓄積して、最適な並列処理のために推奨される最大値よりも大きいファイルを取り込む場合は、小さいファイルをトリガーするようにバッファーサイズを縮小することができます。バッファー間隔の設定を60秒(最小値)に維持すると、ファイルの作成が過剰になったり、待ち時間が長くなったりすることを回避できます。

区切りテキストファイルの準備

ロードする区切りテキスト(CSV)ファイルを準備するときは、次のガイドラインを考慮してください。

  • UTF-8がデフォルトの文字セットですが、追加のエンコードがサポートされています。 ENCODING ファイル形式オプションを使用して、データファイルの文字セットを指定します。詳細については、 CREATE FILE FORMAT をご参照ください。

  • 区切り文字を含むフィールドは、引用符(一重または二重)で囲む必要があります。データに一重引用符または二重引用符が含まれる場合、それらの引用符はエスケープする必要があります。

  • キャリッジリターンは、通常、Windowsシステム上で行末を示す改行文字(\r \n)と組み合わせて導入されます。キャリッジリターンを含むフィールドも引用符で囲む必要があります(一重または二重)。

  • 各行の列数は一貫している必要があります。

半構造化データファイルとサブカラム化

半構造化データが VARIANT 列に挿入されると、Snowflakeは特定のルールを使用して、可能な限り多くのデータを列指向形式で抽出します。残りのデータは、解析された半構造化構造の単一の列として格納されます。

デフォルトでは、Snowflakeはテーブルごと、パーティションごとに最大200個の要素を抽出します。この制限を増やすには、 Snowflakeサポート にお問い合わせください。

抽出されない要素

現在、次の特性を持つ要素は列に抽出 されません

  • 単一の「null」値を含む要素は列に抽出されません。これは、値が欠落している要素ではなく、列指向形式で表される「null」値をともなう要素に適用されます。

    このルールは、情報が失われないことを保証します(つまり、 VARIANT「null」値と SQL NULL 値の差は失われません)。

  • 複数のデータ型を含む要素。例:

    1行の foo 要素には数字が含まれています。

    {"foo":1}
    
    Copy

    別の行の同じ要素には文字列が含まれます。

    {"foo":"1"}
    
    Copy

抽出がクエリに与える影響

半構造化要素に対してクエリを実行すると、Snowflakeの実行エンジンは、要素が抽出されたかどうかによって異なる動作をします。

  • 要素が列に抽出された場合、エンジンは抽出された列のみをスキャンします。

  • 要素が列に抽出 されなかった 場合、実行エンジンは JSON 構造全体をスキャンし、各行で構造を走査して値を出力する必要があります。これはパフォーマンスに影響します。

抽出されなかった要素へのパフォーマンスの影響を避けるには、次を行います。

  • それらをロードする 前に、「null」値を含む半構造化データ要素をリレーショナル列に抽出します。

    または、ファイルの「null」値が欠損値を示しており、他の特別な意味がない場合、半構造化データファイルをロードするときに ファイル形式オプション STRIP_NULL_VALUES を TRUE に設定することをお勧めします。このオプションは、「null」値を含む OBJECT 要素または ARRAY 要素を削除します。

  • それぞれの一意の要素が、その形式に固有である単一のデータ型の値を格納していることを確認してください(例えば、 JSON の文字列または数)。

数値データのガイドライン

  • コンマなどの埋め込み文字(例: 123,456)は避けます。

  • 数値に小数部が含まれる場合、整数部と小数点で区切る必要があります(例: 123456.789)。

  • Oracleのみ。Oracleの NUMBER または NUMERIC 型は、任意のスケールを許可します。つまり、データ型が精度またはスケールで定義されていなくても、小数成分を持つ値を受け入れます。一方、Snowflakeでは、小数部分を持つ値用に設計された列は、小数部分を保持するスケールで定義する必要があります。

日付とタイムスタンプのデータガイドライン

  • 日付、時刻、タイムスタンプデータのサポートされている形式については、 日付と時刻の入出力形式 をご参照ください。

  • Oracleのみ。Oracle DATE データ型には、日付 または タイムスタンプ情報を含めることができます。Oracleデータベースに時間関連情報も保存する DATE 列が含まれている場合、これらの列を DATEではなくSnowflakeの TIMESTAMP データ型にマップします。

注釈

Snowflakeは、ロード時に一時的なデータ値をチェックします。無効な日付、時刻、およびタイムスタンプ値(例: 0000-00-00)ではエラーが発生します。