Data Engineer Associate — 第 7 章
この章で学ぶこと
この章に出てくる用語
ソース側の担当者が JSON にフィールドを一つ足す。それだけで夜間バッチが朝には止まっている、あるいは黙って列が捨てられる。どちらが起きるかは書き込み先の設定で決まります。Delta Lake が既定で選んでいるのは「止まる方」で、これをスキーマ強制 (schema enforcement) と呼びます。この節では書き込み側の規則だけを片付けます。ファイルを読む側の話は次の節からです。
列が id と name の二つしかない Delta 表に、amount を足した DataFrame を追記してみます。
df_new = spark.createDataFrame(
[(1, 'A', 100), (2, 'B', 200)],
['id', 'name', 'amount'])
df_new.write.format('delta') \
.mode('append') \
.save('/Volumes/main/raw/sales')結果は `AnalysisException` です。amount が自動で追加されることはなく、amount が黙って捨てられることもありません。壊れた形のデータを下流へ流さないことを優先した設計で、試験では「mergeSchema を指定していない append の結果はどうなるか」という形で繰り返し問われます。答えは常に書き込みが失敗するです。「追加列は警告なしに無視される」「新列が自動で追加される」「テーブルが上書きされる」はすべて誤りの選択肢として並びます。
強制を恒久的に切るのではなく、この書き込みに限って進化を許すと宣言するのが Delta の作法です。手段は四つあり、効く範囲と危険度が違います。
| 手段 | 書き方 | 効く範囲と挙動 | 既定 |
|---|---|---|---|
| 書き込みオプション | `.option("mergeSchema", "true")` | その 1 回の書き込みだけ。ソースにあってターゲットに無い列をスキーマ末尾に追加する | false |
| セッション設定 | `spark.databricks.delta.schema.autoMerge.enabled` | そのセッションの全書き込みに効く。Databricks はこの方法を本番で使うことを推奨していない | false |
| 上書きオプション | `.option("overwriteSchema", "true")` | overwrite 時にスキーマとパーティション定義ごと置き換える。動的パーティション上書き (書き込むデータに含まれるパーティションだけを差し替えるモード) とは併用できない | false |
| DDL | `ALTER TABLE ... ADD COLUMNS` | データを書く前に表定義そのものを変える。`FIRST` や `AFTER 列名` で挿入位置を指定できる | — |
ここで問われる判断は「安全に新しい列を足す方法を選べ」という形です。正解になるのは `mergeSchema` と `ALTER TABLE ... ADD COLUMNS` の二つで、`overwriteSchema` は表定義ごと差し替える破壊的な操作なので「安全な追加」の答えにはなりません。`ALTER TABLE` で追加した列は nullability が既定で true、つまり NULL を許す列になり、既存行の値は NULL のままです。
ALTER TABLE bronze.sales
ADD COLUMNS (amount DECIMAL(18,2) COMMENT '税抜金額' AFTER name);ここまでの四つはどれも列を足す方向にしか働きません。`mergeSchema` で追加された列は表スキーマの末尾に付きます。列の改名と削除をしたい場合は列マッピング (物理ファイル上の列名と論理的な列名を切り離す機能) を有効にしたうえで `ALTER TABLE ... RENAME COLUMN` と `ALTER TABLE ... DROP COLUMN` を使います。しかも `DROP COLUMN` はメタデータ上で列を消すだけで、ファイルの中のデータは残ります。物理的に消すには `REORG TABLE` のあとに `VACUUM` が要ります。セッション設定の `autoMerge.enabled` が本番向きでないのも同じ理由で、列名を打ち間違えたまま書き込むと、そのタイプミスがそのまま表定義として定着してしまいます。
`MERGE` と `INSERT` には専用の句があり、対応バージョンが別々なので数字だけ押さえます。SQL の `MERGE WITH SCHEMA EVOLUTION` 句は Databricks Runtime 15.2 以降、Python と Scala のテーブル API で `.withSchemaEvolution()` を挟む書き方は Databricks Runtime 15.4 LTS 以降、`INSERT WITH SCHEMA EVOLUTION` は `Databricks Runtime 18.1` 以降です。ここを取り違える設問が出ます。
この三つは名前が似ていますが、働く場所も、失敗したときに起きることも別です。混同したまま設問を読むと、選択肢が全部それらしく見えてしまいます。
| 用語 | 働く場所 | 何を決めるか | 典型的な設定 |
|---|---|---|---|
| スキーマ推論 | 読み取り側 (ファイルを読む瞬間) | ファイルの中身から列名と型を組み立てる。JSON や CSV のように型情報を持たない形式で必要になる | `cloudFiles.schemaLocation` / `cloudFiles.inferColumnTypes` |
| スキーマ強制 | 書き込み側 (Delta 表に書く瞬間) | 表定義と違う形の DataFrame を拒否する。既定で有効 | 設定不要 (常時働く) |
| スキーマ進化 | 書き込み側 | 強制の例外として、この書き込みに限り列の追加を認める | `mergeSchema` / `ALTER TABLE ADD COLUMNS` |
切り分けは症状で付きます。エラーメッセージに列名と型の対応表が出て書き込みが止まっているなら強制側、エラーは出ないのに全列が STRING になっているなら推論側です。読み取り側が新しい列を認識できていなければ、書き込み側で `mergeSchema` をいくら立てても列は増えません。スキーマ事故は、この二層のどちらで詰まっているかを決めるところから始まります。
メダリオンアーキテクチャ (Bronze・Silver・Gold の三層でデータを磨いていく設計) では、強制をかける場所も決まっています。Bronze はソースの生データをロスレスに残す層なので、パースと最小限の型付けだけにとどめ、検証は緩くします。正規化・重複排除・スキーマ強制と品質ルール (Expectations) は Silver 層に置きます。Bronze で厳格に弾くと、弾かれたデータが手元に残らず再処理ができなくなります。Delta 側のスキーマ進化そのもの、型の拡張、列マッピング、制約の詳細は当サイトの「Delta スキーマ進化」「Delta 制約」の記事で扱っているので、深掘りはそちらに送ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
列を追加した DataFrame を mergeSchema なしで既存 Delta 表に append すると になります。
セッション全体でスキーマの自動マージを許可する設定は で、既定は false です。
SQL の MERGE WITH SCHEMA EVOLUTION 句が使えるのは Databricks Runtime 以降です。
Auto Loader を本番に載せたチームがまず驚くのは、金額のはずの列がすべて文字列になっていること、次に、上流が列を一つ足した翌朝にストリームが止まっていることです。どちらも設定を間違えたわけではなく、既定値どおりの動作です。この節では、その既定値を数値と値の名前で覚えます。試験がこの領域から出す問題は、ほとんどが「オプション名」「既定値」「モードの挙動」の三つに集約されます。
Auto Loader は入力ディレクトリの全ファイルを読んでスキーマを決めているわけではありません。最初に検出した 50 GB か 1000 ファイルのうち、先に上限へ達した方までをサンプリングして推論します。1 億ファイルあるバケットでも、見るのは先頭のごく一部です。上限は次の二つの Spark 設定で変えられます。
| 設定 | 意味 | 既定 |
|---|---|---|
| `spark.databricks.cloudFiles.schemaInference.sampleSize.numBytes` | 推論に使うバイト数の上限。`10gb` のようなバイト文字列で指定する | 50 GB |
| `spark.databricks.cloudFiles.schemaInference.sampleSize.numFiles` | 推論に使うファイル数の上限。整数で指定する | 1000 |
この上限があるせいで、サンプルに現れなかった列や、後から届いたファイルにしかない型は推論から漏れます。漏れた分をどう扱うかが、このあとの進化モードと救済列の役割です。
JSON・CSV・XML のように型情報を持たない形式では、Auto Loader は入れ子フィールドを含む全列を文字列として推論します。「数値のはずの列が全部 STRING になった」という設問はこの仕様を突いたもので、原因は `cloudFiles.inferColumnTypes` が既定 false であることです。true にするとサンプルデータから具体的な型を推論します。schemaLocation を指定し忘れたせいではありませんし、救済列が型を奪っているわけでもありません。
スキーマ推論と進化を使うには `cloudFiles.schemaLocation` が必須です。指定したパスに推論したスキーマとその変遷が保存され、これを省くとストリーム再起動のたびに推論をやり直すことになり、進化モードも成立しません。
df = (spark.readStream.format("cloudFiles")
.option("cloudFiles.format", "json")
.option("cloudFiles.schemaLocation", "/Volumes/main/ops/_schemas/events")
.option("cloudFiles.inferColumnTypes", "true")
.option("cloudFiles.schemaHints", "amount DOUBLE, user_info.dob DATE")
.option("cloudFiles.rescuedDataColumn", "_rescue")
.load("/Volumes/main/raw/events"))新しい列が現れたときに何をするかを決めるのが `cloudFiles.schemaEvolutionMode` です。長く 4 値と説明されてきましたが、型の拡張を伴うモードが加わって現在は 5 値あります。
| 値 | 新列を検出したときの挙動 | 既定になる条件 |
|---|---|---|
| `addNewColumns` | スキーマに新列を追加したうえで `UnknownFieldException` を投げてストリームを止める。再起動すると新しいスキーマで取り込みを再開する | スキーマを明示していないとき |
| `addNewColumnsWithTypeWidening` | addNewColumns と同じ動きに加え、int から long のようなサポートされた型の拡張も行う。拡張できない変更は救済列へ回る | — |
| `rescue` | スキーマを一切進化させない。新列はすべて救済列に入り、スキーマ変更でストリームが失敗することはない | — |
| `failOnNewColumns` | 失敗して停止する。人がスキーマを更新するか問題のファイルを取り除くまで再起動できない | — |
| `none` | スキーマを進化させず、新しい列を無視する。`rescuedDataColumn` を設定していなければ救済もされない | スキーマを明示したとき |
引っかかりやすいのが `addNewColumns` と `failOnNewColumns` の区別です。どちらもストリームは落ちます。違うのは再起動したときで、addNewColumns は新列を取り込んで続きから走り、failOnNewColumns は人手でスキーマを直すまで走りません。Lakeflow Jobs (Databricks のジョブ実行基盤) のタスク再試行と addNewColumns を組み合わせると、人が介在せずに列追加を吸収できます。`PERMISSIVE` は後述するパーサーのモード名であって schemaEvolutionMode の値ではなく、誤答の常連です。
扱う範囲にも限りがあります。schemaEvolutionMode が面倒を見るのは列の追加と型の拡張までで、ソース側で列が削除されたことを検知して表から消す機能ではありません。また、ディレクトリ構造から取り出す Hive 形式のパーティション列は進化の対象外で、増やしたいときは `cloudFiles.partitionColumns` にカンマ区切りで明示します。
ここまでは推論に任せる前提でした。`.schema(...)` で自分のスキーマを渡すと、既定値が同時に三つ変わります。
| 設定 | 推論に任せる場合 | スキーマを渡す場合 |
|---|---|---|
| `schemaEvolutionMode` | `addNewColumns` | `none` |
| 救済列 | `_rescued_data` が自動で付く | `rescuedDataColumn` の指定が必要 |
| `schemaHints` | 指定した列だけ型を固定 | 適用されない |
つまり固定スキーマにして何も足さないと、新しい列は進化もせず救済もされず静かに消えます。「スキーマを固定したらデータが欠けた」という障害報告の大半はこの組み合わせで、不具合ではありません。固定したまま取りこぼしを見えるようにするなら、`rescuedDataColumn` を明示するか、モードを `rescue` か `failOnNewColumns` に切り替えます。
スキーマに収まらなかった値を捨てないための逃がし場所が救済列です。既定の列名は `_rescued_data` で、`cloudFiles.rescuedDataColumn` に別名を渡せば変えられます。中身は救済された列と、そのレコードのソースファイルパスを含む JSON です。対象になるのは、推論または宣言したスキーマに存在しない列、型が合わずキャストできなかった値、大文字小文字だけが違う列名の三種類です。
破損レコードの扱いとは別物なので混ぜないでください。JSON や CSV のリーダーには `mode` オプションがあり、既定は `PERMISSIVE`、壊れたレコードは `columnNameOfCorruptRecord` で指定した列 (既定名 `_corrupt_record`) に入ります。`DROPMALFORMED` で捨てられたり `FAILFAST` で落ちたりするのは、JSON や CSV として本当に壊れているレコードだけで、単なる型の食い違いはこちらではなく救済列に回ります。「想定外のカラムに値が入る」という現象の正体はたいてい救済列で、`SELECT _rescued_data FROM ...` で中身を確認できます。
推論が STRING や DOUBLE に倒れて困る列を名指しで直すのが `cloudFiles.schemaHints` です。値は JSON ではなく SQL の DDL 表記で、`"amount DOUBLE, tags map<string,string>"` のようにカンマ区切りで並べ、`user_info.dob DATE` のような入れ子のパスも指定できます。指定しなかった列は通常どおり推論されます。ヒントを書いたのに型が変わらないときは、列名の綴り違いか別名で書いているのが原因なので、正しい「列名 型」で書き直し、schemaLocation を保ったまま再起動するのが定石です。チェックポイントを消してやり直すのは、再処理コストと重複を招くだけです。
取り込みが終わったファイルを入力ディレクトリに置きっぱなしにすると、一覧取得のコストが延々と増えます。`cloudFiles.cleanSource` はこれを自動で片付けるオプションで、Databricks Runtime 16.4 以降で使えます。
| オプション | 取りうる値・意味 | 既定 |
|---|---|---|
| `cloudFiles.cleanSource` | `OFF` / `DELETE` / `MOVE` の 3 択 | OFF |
| `cloudFiles.cleanSource.moveDestination` | MOVE のときの退避先。ソースディレクトリの子であってはならず、ソースと同じ外部ロケーション・ボリューム・DBFS マウント内である必要がある | なし |
| `cloudFiles.cleanSource.retentionDuration` | 処理済みになってから片付けの対象になるまでの猶予。`14 days` のように書く。DELETE では 7 日より長い値が必須 | 30 days |
MOVE の制約は言い換えると一つです。バケットやコンテナをまたぐ移動はサポートされません。
| オプション | 役割 | 既定 |
|---|---|---|
| `cloudFiles.maxFilesPerTrigger` | 1 トリガーで処理する新規ファイル数の上限 | 1000 |
| `cloudFiles.maxBytesPerTrigger` | 1 トリガーで処理するバイト数の上限。両方指定すると、どちらか一方の上限に達するのに必要なファイル数まで処理する | なし |
| `cloudFiles.includeExistingFiles` | ストリーム開始時点で既にあるファイルを対象に含めるか | true |
| `cloudFiles.allowOverwrites` | 処理済みファイルが同名で上書きされたとき再処理するか | false |
| `cloudFiles.validateOptions` | 未知のオプション名や矛盾する組み合わせを起動時に検証してエラーにする | true |
| `cloudFiles.maxFileAge` | 重複排除のためにファイルイベントを追跡し続ける期間。短くしすぎると追跡から外れた古いファイルが再検出され重複取り込みになる。Databricks は 90 日程度の余裕を持たせることを勧めている | なし |
| `cloudFiles.backfillInterval` | ファイル通知の取りこぼしを補うバックフィルの間隔 | なし |
| `cloudFiles.useStrictGlobber` | 他の Spark ファイルソースと同じグロブ解釈に揃える | false |
取り込み状況の確認には `cloud_files_state()` テーブル関数を使います。チェックポイントのパスか `TABLE(ストリーミングテーブル名)` を渡すと path・size・discovery_time・commit_time・ingestion_state などの列が返り、commit_time が NULL のファイルはまだ処理されていないことを意味します。ingestion_state には INGESTED や PROCESSING、SKIPPED_CORRUPTED といった値が入ります。バックログの大きさは Streaming Query Listener が報告する `numFilesOutstanding` と `numBytesOutstanding` で測ります。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
スキーマを明示していないときの cloudFiles.schemaEvolutionMode の既定は です。
rescuedDataColumn に退避されるのは、未知の列・型不一致の値・ の三種類です。
Auto Loader のスキーマ推論は、最初に検出した のうち先に上限へ達した方までをサンプリングします。
SQL しか書かないチームが最初に困るのは、たいてい同じ場面です。ジョブが落ちたので手で流し直したら同じ行が二重に入った。毎晩ディレクトリをまるごと指定したいが、昨日のファイルまで読み直されるのが怖い。`COPY INTO` は、この「同じものを二度入れたくない」を SQL 一文で解決するコマンドです。Auto Loader がストリーミング側の道具なのに対して、COPY INTO はバッチの世界で冪等性を担保する道具です。
COPY INTO target_table [ BY POSITION | ( col_name [, col_name ...] ) ]
FROM { source_clause | ( SELECT expression_list FROM source_clause ) }
FILEFORMAT = data_source
[ VALIDATE [ ALL | num_rows ROWS ] ]
[ FILES = ( file_name [, ...] ) | PATTERN = glob_pattern ]
[ FORMAT_OPTIONS ( { data_source_reader_option = value } [, ...] ) ]
[ COPY_OPTIONS ( { copy_option = value } [, ...] ) ]
source_clause
source [ WITH ( [ CREDENTIAL ... ] [ ENCRYPTION ... ] ) ]`FILEFORMAT` は公式ドキュメントの中で記述が食い違っているので両方覚えます。SQL 構文リファレンスが列挙しているのは CSV / JSON / AVRO / ORC / PARQUET / TEXT / BINARYFILE の 7 種類ですが、COPY INTO の概要ページは XML を含めた 8 種類を挙げ、XML のページには `FILEFORMAT = XML` の実例が載っています。XML は Databricks Runtime 14.3 以降で、通常は `FORMAT_OPTIONS ('rowTag' = '...')` を併用します。左辺がターゲット表、右辺がソース URI で、これを逆に書いた選択肢が誤答として並びます。
COPY INTO は既存の Delta 表しか受け付けません。存在しない表名を書いても表は自動作成されず、一時ビューにも外部表にもなりません。では取り込むデータの列構成が未確定のときはどうするか。ドキュメントが示す手順は、列を持たない空のプレースホルダ Delta 表を先に作り、mergeSchema を true にして推論させるというものです。スキーマを省略できるのは Databricks Runtime 11.3 LTS 以降で、スキーマ進化に対応した形式に限られます。
CREATE TABLE IF NOT EXISTS my_pipe_data;
COPY INTO my_pipe_data
FROM 's3://my-bucket/pipeData'
FILEFORMAT = CSV
FORMAT_OPTIONS ('mergeSchema' = 'true', 'delimiter' = '|', 'header' = 'true')
COPY_OPTIONS ('mergeSchema' = 'true');この空表は COPY INTO 専用です。ドキュメントは、スキーマの無い Delta 表への書き込みに `INSERT INTO` と `MERGE INTO` はサポートされないと明記しています。データが入ってはじめて普通の表として問い合わせられます。権限面では、アカウント管理者がクラウドストレージへのアクセスを構成したうえで、実行するユーザーに対象のカタログ・スキーマ・ボリュームに対する CREATE TABLE 権限が必要です。
COPY INTO の最大の性質は再実行しても重複しないことです。仕組みは単純で、ソースの場所にあるファイルのうち既に読み込んだものは次回以降スキップされるだけです。記録はターゲット表側に置かれ、COPY INTO が作ったメタデータファイルは Databricks Runtime 15.2 以降なら `VACUUM` で掃除できます。ファイル内容のハッシュを毎回計算しているわけでも、内部で MERGE に切り替わっているわけでもありません。帰結が三つ出ます。
この冪等性を意図的に外すのが `COPY_OPTIONS ('force' = 'true')` です。既定は false で、true にすると取り込み済みかどうかにかかわらず全ファイルが読み込まれます。書き換え後の内容を反映したいときやバックフィルには必要ですが、本番ジョブに付けっぱなしにすると重複が積み上がります。
運用の側から冪等性を壊す例も覚えます。毎回 `DROP TABLE` と `CREATE TABLE` で作り直す、事前に `TRUNCATE TABLE` で空にする、ファイル名に毎回タイムスタンプを付ける。どれも記録を消すか鍵を変えるので全件再取り込みになります。冪等性はファイルのパスを鍵にして成立していると押さえてください。
同じ「二度取り込まない」でも、Auto Loader とは記録場所が違います。COPY INTO はターゲット表側、Auto Loader はチェックポイント内のキーバリューストア (RocksDB) です。記録が別々である以上、同じ表に両方を常用すると互いの履歴を参照せず二重取り込みの温床になります。ただしドキュメントは、Auto Loader のストリームを走らせたまま COPY INTO で一部のファイルだけ入れ直す使い方は認めています。
この振り分けは単独で一問になるほど頻出です。
| 句 | 誰に渡るか | 指定できるもの |
|---|---|---|
| `FORMAT_OPTIONS` | FILEFORMAT に対応する Spark のデータソースリーダー | `header` / `delimiter` / `multiLine` / `ignoreCorruptFiles` など、読み方に関するすべて |
| `COPY_OPTIONS` | COPY INTO コマンド自身 | `force` (既定 false) と `mergeSchema` (既定 false) の 2 つだけ |
COPY_OPTIONS に二つしか無いと知っていれば、`COPY_OPTIONS ('header' = 'true')` や `COPY_OPTIONS ('multiLine' = 'true')` を並べた選択肢は読んだ瞬間に消せます。「破損ファイルを飛ばして続行したい」は `FORMAT_OPTIONS ('ignoreCorruptFiles' = 'true')`、「複数行にまたがる整形済み JSON を読みたい」は `FORMAT_OPTIONS ('multiLine' = 'true')` です。CSV の `header` も JSON の `multiLine` も既定は false で、明示しないと先頭行がデータ行になります。
やっかいなのは `mergeSchema` が両方の句に書けることです。FORMAT_OPTIONS 側は複数ファイル間でスキーマを突き合わせる読み取り時の指定、COPY_OPTIONS 側はターゲット表のスキーマを進化させる指定です。列が増えたときに表を追随させたいなら COPY_OPTIONS 側。なお Auto Loader の救済列は COPY INTO では使えないので、取りこぼしたくないなら mergeSchema で表側を広げるしかありません。
本番表へ書く前に確かめたいときに使うのが `VALIDATE` 句です。Databricks Runtime 10.4 LTS 以降で使え、付けるとデータは検証されるだけでテーブルには一切書き込まれません。検証されるのはパース可否、表のスキーマと一致するか (進化が必要か)、nullability と CHECK 制約を満たすか、の三点です。
「書き込む前に確かめたい」に対して一時テーブルへ COPY INTO する案は、実際に書き込みが起きるので不正解です。
ソースの列名がターゲット表と一致しないが並び順は一致している。この状況を解決するのが `BY POSITION` で、ソース列とターゲット列を序数位置で対応付け、型のキャストも自動で行います。使えるのはヘッダーなし CSV だけで、`FILEFORMAT = CSV` の指定と `FORMAT_OPTIONS ("headers" = "false")` が必要です (これが既定値でもあります)。
COPY INTO bronze.sales BY POSITION
FROM 's3://my-bucket/headerless/'
FILEFORMAT = CSV;表記に注意します。BY POSITION で書くのは複数形の `headers` で、CSV リーダーの `header` とは別のキーです。誤答肢に並ぶ `FORMAT_OPTIONS ('header' = 'false')` は先頭行をデータとして読む指定でしかなく、列名の食い違いは解決しません。対応付けではターゲット表の IDENTITY 列 (連番が自動採番される列) と GENERATED 列 (式から自動計算される列) が無視され、残った列数とソース列数が合わなければエラーになります。
| 句 | 書き方 | 制約 |
|---|---|---|
| `FILES` | ロードするファイル名を列挙する | 指定できるのは 1000 件まで |
| `PATTERN` | グロブパターン (ワイルドカードでファイル名をまとめて指定する書き方) でソースディレクトリ内を絞る | `?` `*` `[abc]` `[a-z]` `[^a]` `{ab,cd}` が使える |
この二つは同時に指定できません。FILES で明示したファイルでも冪等性の判定は生きていて、取り込み済みなら黙ってスキップされます。PATTERN は読み込む対象を選ぶ句であり、除外を書く句でも履歴管理を無効化する句でもありません。
ソースパスへのアクセス資格情報は、FROM 句のパスに続けて `WITH` で渡します。`COPY_OPTIONS` や `FORMAT_OPTIONS` に `credential` というオプションは存在しません。名前付き資格情報のほかに一時資格情報 (AWS なら `AWS_ACCESS_KEY` / `AWS_SECRET_KEY` / `AWS_SESSION_TOKEN`、Azure なら `AZURE_SAS_TOKEN`) も渡せ、同じ括弧に `ENCRYPTION` も並べられます。
COPY INTO bronze.sales
FROM 's3://my-bucket/raw/' WITH ( CREDENTIAL my_named_credential )
FILEFORMAT = PARQUET;ロードしながら型を変えたり列を落としたりしたい場合は、FROM 句にサブクエリを書きます。オプション句は `key = value` しか受け取らないので、式を書ける場所はここだけです。
COPY INTO my_delta_table
FROM (SELECT to_date(dt) dt, event as measurement, quantity::double
FROM 's3://my-bucket/avroData')
FILEFORMAT = AVRO;同じ表に対する複数の COPY INTO は、それぞれが扱う入力ファイルの集合が互いに素 (共通のファイルを一つも含まない状態) であれば、いずれも最終的に成功します。重なるとトランザクション競合になります。ただし 1 つのコマンドに複数ファイルを渡す方が速いため、性能目的の並行実行は推奨されていません。
選定の目安は明快です。時間をかけて取り込むファイルが数千のオーダーなら COPY INTO、数百万以上が見込まれるなら Auto Loader。スキーマが頻繁に変わる場合も Auto Loader が向きます。SQL だけでより拡張性の高い形を求めるなら、ドキュメントが示す代替は `CREATE STREAMING TABLE` と `read_files` によるストリーミングテーブルです。
| 観点 | Delta への書き込み | Auto Loader | COPY INTO |
|---|---|---|---|
| 既定の反応 | AnalysisException で拒否 | `UnknownFieldException` で停止し再起動で追加 | 新列は表に取り込まれない |
| 進化を許す指定 | `mergeSchema` オプション | `cloudFiles.schemaEvolutionMode` | `COPY_OPTIONS ('mergeSchema' = 'true')` |
| 捨てずに退避する仕組み | なし | `_rescued_data` 列 | なし |
| 重複防止の鍵 | 書き込み側の実装しだい | チェックポイント内の RocksDB | ターゲット表側のロード済みファイル記録 |
| 実行形態 | バッチ / ストリーミング | Structured Streaming のソース | SQL のバッチコマンド |
並べると、救済列を持つのは Auto Loader だけだと分かります。優劣ではなく、必要なのが救済かチェックポイント不要かで選びます。
確認 — 穴あけ 3 問
0 / 3
空欄を押すと選択肢が出ます。間違えても減点はありません。
COPY INTO の COPY_OPTIONS に指定できるのは の 2 つだけです。
取り込み済みのファイルがソース側で書き換えられた場合、次回の COPY INTO では 。
COPY INTO の FILES 句で指定できるファイル名は までで、PATTERN 句とは同時に指定できません。
この章のまとめ
この端末にだけ保存されます(登録不要)
← 前の章
流れ込むデータを受け止める — Structured Streaming と Auto Loader のファイル検出
次の章 →
ファイル以外からも取り込む — read_files・Lakeflow Connect・JDBC と API
この章の根拠
最終確認 2026-08-09 / 対応バージョン DEA 2026-05-04 改訂版
コース全体