共用方式為


更新 Delta Lake 資料表結構描述

Delta Lake 可讓您更新資料表的結構描述。 支援下列類型的變更:

  • 新增資料列 (在任意位置)
  • 重新排序現有的數據行
  • 重新命名現有的數據行

您可以明確使用 DDL 或隱含地使用 DML 來進行這些變更。

重要

Delta 數據表架構的更新是與所有並行 Delta 寫入作業衝突的作業。

更新 Delta 表格架構時,從該表格讀取的串流將會終止。 如果您想要讓資料流程繼續,您必須加以重新啟動。 如需建議的方法,請參閱 結構化串流的生產考慮。

明確更新結構描述以新增資料行

ALTER TABLE table_name ADD COLUMNS (col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)

根據預設,Null 屬性為 true

若要將資料行加入巢狀欄位,請使用:

ALTER TABLE table_name ADD COLUMNS (col_name.nested_col_name data_type [COMMENT col_comment] [FIRST|AFTER colA_name], ...)

例如,如果執行 ALTER TABLE boxes ADD COLUMNS (colB.nested STRING AFTER field1) 前的架構為:

- root
| - colA
| - colB
| +-field1
| +-field2

之後的架構為:

- root
| - colA
| - colB
| +-field1
| +-nested
| +-field2

注意

僅支持結構新增巢狀數據行。 不支援數位和對應。

明確更新結構描述以變更資料行註解或排序

ALTER TABLE table_name ALTER [COLUMN] col_name (COMMENT col_comment | FIRST | AFTER colA_name)

若要變更巢狀欄位中的數據行,請使用:

ALTER TABLE table_name ALTER [COLUMN] col_name.nested_col_name (COMMENT col_comment | FIRST | AFTER colA_name)

例如,如果執行 ALTER TABLE boxes ALTER COLUMN colB.field2 FIRST 前的架構為:

- root
| - colA
| - colB
| +-field1
| +-field2

之後的架構為:

- root
| - colA
| - colB
| +-field2
| +-field1

明確更新結構描述以取代資料行

ALTER TABLE table_name REPLACE COLUMNS (col_name1 col_type1 [COMMENT col_comment1], ...)

例如,執行下列 DDL 時:

ALTER TABLE boxes REPLACE COLUMNS (colC STRING, colB STRUCT<field2:STRING, nested:STRING, field1:STRING>, colA STRING)

如果之前的架構為:

- root
| - colA
| - colB
| +-field1
| +-field2

之後的架構為:

- root
| - colC
| - colB
| +-field2
| +-nested
| +-field1
| - colA

明確更新架構以重新命名數據行

注意

這項功能適用於 Databricks Runtime 10.4 LTS 和更新版本。

若要重新命名數據行而不重寫任何數據行的現有數據,您必須啟用資料表的數據行對應。 請參閱 使用 Delta Lake 數據行對應來重新命名和卸除數據行。

若要重新命名資料列:

ALTER TABLE table_name RENAME COLUMN old_col_name TO new_col_name

若要重新命名巢狀欄位:

ALTER TABLE table_name RENAME COLUMN col_name.old_nested_field TO new_nested_field

例如,當您執行下列命令時:

ALTER TABLE boxes RENAME COLUMN colB.field1 TO field001

如果之前的架構為:

- root
| - colA
| - colB
| +-field1
| +-field2

之後的架構為:

- root
| - colA
| - colB
| +-field001
| +-field2

請參閱 使用 Delta Lake 數據行對應來重新命名和卸除數據行。

明確更新架構以卸除數據行

注意

這項功能適用於 Databricks Runtime 11.3 LTS 和更新版本。

若要將數據行卸除為僅限元數據的作業,而不需重寫任何數據檔,您必須啟用數據表的數據行對應。 請參閱 使用 Delta Lake 數據行對應來重新命名和卸除數據行。

重要

從元數據卸除數據行並不會刪除檔案中數據行的基礎數據。 若要清除卸除的數據行數據,您可以使用 REORG TABLE 來重寫檔案。 然後 ,您可以使用 VACUUM 來實際刪除包含已卸載數據行資料的檔案。

若要卸除數據行:

ALTER TABLE table_name DROP COLUMN col_name

若要卸除多個數據行:

ALTER TABLE table_name DROP COLUMNS (col_name_1, col_name_2)

明確更新架構以變更數據行類型或名稱

您可以藉由重寫資料表來變更資料行的類型或名稱,或卸除數據行。 若要這樣做,請使用 overwriteSchema 選項。

下列範例顯示變更資料行類型:

(spark.read.table(...)
  .withColumn("birthDate", col("birthDate").cast("date"))
  .write
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable(...)
)

下列範例顯示變更資料列名稱:

(spark.read.table(...)
  .withColumnRenamed("dateOfBirth", "birthDate")
  .write
  .mode("overwrite")
  .option("overwriteSchema", "true")
  .saveAsTable(...)
)

啟用架構演進

您可以執行下列其中一項來啟用架構演進:

  • .option("mergeSchema", "true")將 設定為 Spark DataFrame writewriteStream作業。 請參閱 啟用架構演進以新增數據行的寫入。
  • 使用 MERGE WITH SCHEMA EVOLUTION 語法。 請參閱 合併的架構演進語法。
  • 將 Spark conf spark.databricks.delta.schema.autoMerge.enabled 設定為 true 目前的 SparkSession。

Databricks 建議為每個寫入作業啟用架構演進,而不是設定 Spark conf。

當您使用選項或語法在寫入作業中啟用架構演進時,這會優先於Spark conf。

注意

語句沒有架構演進子句 INSERT INTO

啟用寫入的架構演進以新增數據行

啟用架構演進時,來源查詢中存在但目標數據表遺漏的數據行會自動新增為寫入交易的一部分。 請參閱 啟用架構演進

附加新數據行時,會保留大小寫。 新的數據行會新增至數據表架構的結尾。 如果其他數據行位於結構中,則會附加至目標數據表中結構結尾。

下列範例示範搭配自動載入器使用 mergeSchema 選項。 請參閱 什麼是自動載入器?

(spark.readStream
  .format("cloudFiles")
  .option("cloudFiles.format", "json")
  .option("cloudFiles.schemaLocation", "<path-to-schema-location>")
  .load("<path-to-source-data>")
  .writeStream
  .option("mergeSchema", "true")
  .option("checkpointLocation", "<path-to-checkpoint>")
  .trigger(availableNow=True)
  .toTable("table_name")
)

下列範例示範搭配批次寫入作業使用 mergeSchema 選項:

(spark.read
  .table(source_table)
  .write
  .option("mergeSchema", "true")
  .mode("append")
  .saveAsTable("table_name")
)

Delta Lake merge 的自動架構演進

架構演進可讓使用者解決合併中目標與源數據表之間的架構不符。 它會處理下列兩種情況:

  1. 源數據表中的數據行不存在於目標數據表中。 新的數據行會新增至目標架構,並使用來源值插入或更新其值。
  2. 目標數據表中的數據行不存在於源數據表中。 目標架構維持不變;其他目標數據行中的值會維持不變(針對 UPDATE)或設定為 NULL (for INSERT)。

您必須手動啟用自動架構演進。 請參閱 啟用架構演進

注意

在 Databricks Runtime 12.2 LTS 和更新版本中,源數據表中存在的數據行和結構字段可以透過名稱來指定或更新動作。 在 Databricks Runtime 11.3 LTS 和以下版本中,只能 INSERT * 使用 或 UPDATE SET * 動作搭配合併進行架構演進。

Databricks Runtime 13.3 LTS 和更新版本中,您可以使用架構演進搭配結構巢狀結構,例如 map<int, struct<a: int, b: int>>

合併的架構演進語法

在 Databricks Runtime 15.2 和更新版本中,您可以使用 SQL 或 Delta 數據表 API 在合併語句中指定架構演進:

SQL

MERGE WITH SCHEMA EVOLUTION INTO target
USING source
ON source.key = target.key
WHEN MATCHED THEN
  UPDATE SET *
WHEN NOT MATCHED THEN
  INSERT *
WHEN NOT MATCHED BY SOURCE THEN
  DELETE

Python

from delta.tables import *

(targetTable
  .merge(sourceDF, "source.key = target.key")
  .withSchemaEvolution()
  .whenMatchedUpdateAll()
  .whenNotMatchedInsertAll()
  .whenNotMatchedBySourceDelete()
  .execute()
)

Scala

import io.delta.tables._

targetTable
  .merge(sourceDF, "source.key = target.key")
  .withSchemaEvolution()
  .whenMatched()
  .updateAll()
  .whenNotMatched()
  .insertAll()
  .whenNotMatchedBySource()
  .delete()
  .execute()

合併與架構演進的範例作業

以下是使用 和不使用架構演進之作業效果的 merge 一些範例。

資料行 查詢 (在 SQL 中) 沒有架構演進的行為 (預設值) 架構演進的行為
目標資料列: key, value

來源資料列: key, value, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET *
WHEN NOT MATCHED
THEN INSERT *
數據表架構保持不變;只會更新/插入數據行keyvalue 資料表架構會變更為 (key, value, new_value)。 具有相符項目的現有記錄會使用 和 valuenew_value 在來源中更新。 新的資料欄會插入架構 (key, value, new_value)
目標資料列: key, old_value

來源資料列: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET *
WHEN NOT MATCHED
THEN INSERT *
UPDATEINSERT 動作會擲回錯誤,因為目標數據行 old_value 不在來源中。 資料表架構會變更為 (key, old_value, new_value)。 具有相符項目的現有記錄會隨著來源中的 更新 new_value 而保持不變 old_value 。 新的記錄會插入指定的keynew_valueNULLold_value
目標資料列: key, old_value

來源資料列: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN MATCHED
THEN UPDATE SET new_value = s.new_value
UPDATE 擲回錯誤,因為數據行 new_value 不存在於目標數據表中。 資料表架構會變更為 (key, old_value, new_value)。 具有相符項目的現有記錄會隨著來源中的 更新 new_value 而維持 old_value 不變,而且已 NULL 針對 new_value輸入不相符的記錄。 請參閱附註 (1)
目標資料列: key, old_value

來源資料列: key, new_value
MERGE INTO target_table t
USING source_table s
ON t.key = s.key
WHEN NOT MATCHED
THEN INSERT (key, new_value) VALUES (s.key, s.new_value)
INSERT 擲回錯誤,因為數據行 new_value 不存在於目標數據表中。 資料表架構會變更為 (key, old_value, new_value)。 新的記錄會插入指定的keynew_valueNULLold_value 已輸入現有記錄 NULLnew_value 保留 old_value 不變。 請參閱附註 (1)

(1) Databricks Runtime 12.2 LTS 和更新版本提供此行為:在此情況下,Databricks Runtime 11.3 LTS 和以下錯誤。

使用 Delta Lake merge 排除數據行

在 Databricks Runtime 12.2 LTS 和更新版本中,您可以在合併條件中使用 EXCEPT 子句來明確排除數據行。 關鍵詞的行為 EXCEPT 會根據是否啟用架構演進而有所不同。

停用架構演進時, EXCEPT 關鍵詞會套用至目標數據表中的數據行清單,並允許從 UPDATEINSERT 動作排除數據行。 排除的資料列會設定為 null

啟用架構演進后, EXCEPT 關鍵詞會套用至源數據表中的數據行清單,並允許從架構演進中排除數據行。 如果目標列在 子句中 EXCEPT ,則來源中不存在的新數據行不會新增至目標架構。 目標中已存在的排除資料列會設定為 null

下列範例示範此語法:

資料行 查詢 (在 SQL 中) 沒有架構演進的行為 (預設值) 架構演進的行為
目標資料列: id, title, last_updated

來源資料列: id, title, review, last_updated
MERGE INTO target t
USING source s
ON t.id = s.id
WHEN MATCHED
THEN UPDATE SET last_updated = current_date()
WHEN NOT MATCHED
THEN INSERT * EXCEPT (last_updated)
比對的數據列會藉由將 last_updated 字段設定為目前日期來更新。 新的數據列會使用 和title的值id插入。 排除的欄位 last_updated 會設定為 null。 欄位 review 會被忽略,因為它不在目標中。 比對的數據列會藉由將 last_updated 字段設定為目前日期來更新。 架構會演進以新增欄位 review。 新的數據列會使用所有來源字段插入,但設定為 null除外last_updated
目標資料列: id, title, last_updated

來源資料列: id, title, review, internal_count
MERGE INTO target t
USING source s
ON t.id = s.id
WHEN MATCHED
THEN UPDATE SET last_updated = current_date()
WHEN NOT MATCHED
THEN INSERT * EXCEPT (last_updated, internal_count)
INSERT 擲回錯誤,因為數據行 internal_count 不存在於目標數據表中。 比對的數據列會藉由將 last_updated 字段設定為目前日期來更新。 欄位 review 會新增至目標數據表,但 internal_count 會忽略欄位。 插入的新資料欄已 last_updated 設定為 null

NullType處理架構更新中的數據行

因為 Parquet 不支援 NullTypeNullType 因此當寫入 Delta 數據表時,數據行會從 DataFrame 卸除,但仍會儲存在架構中。 當收到該數據行的不同數據類型時,Delta Lake 會將架構合併到新的數據類型。 如果 Delta Lake 收到 NullType 現有數據行的 ,則會保留舊的架構,並在寫入期間卸除新的數據行。

NullType 不支援串流。 因為您必須在使用串流時設定架構,這應該非常罕見。 NullType 也不接受複雜型別,例如 ArrayTypeMapType

取代資料表結構描述

根據預設,覆寫數據表中的數據不會覆寫架構。 使用 mode("overwrite") 不使用 replaceWhere覆寫數據表時,您可能仍想要覆寫所寫入數據的架構。 您可以將 選項設定 overwriteSchematrue,以取代資料表的架構和資料分割:

df.write.option("overwriteSchema", "true")

重要

您無法在使用動態分割覆寫時指定 overwriteSchematrue