Delta Lake 生成的欄位

Important

這項功能目前處於 公開預覽版

Delta Lake 產生欄位會自動計算並儲存使用者定義表達式的數值,疊加於表格中其他欄位。 當你寫入資料表但未提供產生欄位的值時,Delta Lake 會自動計算。 如果你提供數值,必須 (<value> <=> <generation expression>) IS TRUE 符合,否則寫入會失敗。 請參閱Azure Databricks 的限制

例如,你可以根據 base_price * 1.1 計算出一個 price_with_tax 欄位,而不需要在寫入時為 price_with_tax 指定資料。

與一般欄位一樣,產生的欄位會實體儲存在資料表的底層資料檔案中。

備註

啟用產生欄位會升級表格撰寫協定。 這可能會影響與外部 Delta Lake 用戶端的相容性。 請參閱 Delta Lake 功能相容性和通訊協定

建立具有生成欄位的數據表

下列範例示範如何使用產生的數據行建立資料表:

SQL

CREATE TABLE default.people10m (
  id INT,
  firstName STRING,
  middleName STRING,
  lastName STRING,
  gender STRING,
  birthDate TIMESTAMP,
  dateOfBirth DATE GENERATED ALWAYS AS (CAST(birthDate AS DATE)),
  ssn STRING,
  salary INT
)

Python

DeltaTable.create(spark) \
  .tableName("default.people10m") \
  .addColumn("id", "INT") \
  .addColumn("firstName", "STRING") \
  .addColumn("middleName", "STRING") \
  .addColumn("lastName", "STRING", comment = "surname") \
  .addColumn("gender", "STRING") \
  .addColumn("birthDate", "TIMESTAMP") \
  .addColumn("dateOfBirth", DateType(), generatedAlwaysAs="CAST(birthDate AS DATE)") \
  .addColumn("ssn", "STRING") \
  .addColumn("salary", "INT") \
  .execute()

Scala

DeltaTable.create(spark)
  .tableName("default.people10m")
  .addColumn("id", "INT")
  .addColumn("firstName", "STRING")
  .addColumn("middleName", "STRING")
  .addColumn(
    DeltaTable.columnBuilder("lastName")
      .dataType("STRING")
      .comment("surname")
      .build())
  .addColumn("lastName", "STRING", comment = "surname")
  .addColumn("gender", "STRING")
  .addColumn("birthDate", "TIMESTAMP")
  .addColumn(
    DeltaTable.columnBuilder("dateOfBirth")
     .dataType(DateType)
     .generatedAlwaysAs("CAST(dateOfBirth AS DATE)")
     .build())
  .addColumn("ssn", "STRING")
  .addColumn("salary", "INT")
  .execute()

支援的表達式

生成表達式可以使用任何確定性 SQL 函式,這些函式對相同輸入總是回傳相同結果。 例如:

  • 算術: base_price * 1.1
  • 字串函數: CONCAT(first_name, ' ', last_name)SUBSTRING(col, 1, 3)
  • 日期函數: CAST(birthDate AS DATE)YEAR(eventTime)

以下函式類型不支援:

  • 用戶定義函式
  • 聚合函數
  • 視窗函數
  • 回傳多列的函式

分區篩選器產生

備註

Databricks 建議所有新的 Delta Lake 資料表都採用液態叢集。 請參閱 針對數據表使用液體叢集

當你用產生的欄位劃分資料表並查詢基底欄位時,Delta Lake 會自動推導出分割過濾器(如果可能的話)。 你不需要明確對產生的分割區欄位進行篩選。 Delta Lake 從基準欄位值推斷出分割範圍。

Databricks Runtime 10.4 LTS 和以下版本需要 Photon。 Databricks Runtime 11.3 LTS 和更新版本不需要 Photon。

以下表達式支援分割濾鏡產生:

  • CAST(col AS DATE)col 的類型是 TIMESTAMP
  • YEAR(col)col 的類型是 TIMESTAMP
  • YEAR(col), MONTH(col) 定義的兩個分割資料行,其 col 的型別為 TIMESTAMP
  • YEAR(col), MONTH(col), DAY(col) 定義的三個分割欄位,其 col 的型別是 TIMESTAMP
  • YEAR(col), MONTH(col), DAY(col), HOUR(col) 定義的四個資料分割欄位,其型別 colTIMESTAMP
  • SUBSTRING(col, pos, len) 且的類型 colSTRING
  • DATE_FORMAT(col, format)col 的類型是 TIMESTAMP
    • 您只能搭配下列模式使用日期格式: yyyy-MMyyyy-MM-dd-HH
    • 在 Databricks Runtime 10.4 LTS 和更新版本中,您也可以使用下列模式: yyyy-MM-dd

範例:單一分割區

例如,假設有下表:

CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
eventDate date GENERATED ALWAYS AS (CAST(eventTime AS DATE))
)
PARTITIONED BY (eventType, eventDate)

如果您接著執行下列查詢:

SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" AND eventTime <= "2020-10-01 12:00:00"

Delta Lake 會自動產生數據分割篩選,如此一來,即使未指定數據分割篩選,上述查詢仍只會讀取數據分割中的數據 date=2020-10-01

使用 EXPLAIN 條款並檢查提供的計畫,看看 Delta Lake 是否會自動產生任何分割過濾器。

範例:多重分割區

例如,假設有下表:

CREATE TABLE events(
eventId BIGINT,
data STRING,
eventType STRING,
eventTime TIMESTAMP,
year INT GENERATED ALWAYS AS (YEAR(eventTime)),
month INT GENERATED ALWAYS AS (MONTH(eventTime)),
day INT GENERATED ALWAYS AS (DAY(eventTime))
)
PARTITIONED BY (eventType, year, month, day)

如果您接著執行下列查詢:

SELECT * FROM events
WHERE eventTime >= "2020-10-01 00:00:00" AND eventTime <= "2020-10-01 12:00:00"

Delta Lake 會自動產生數據分割篩選,如此一來,即使未指定數據分割篩選,上述查詢仍只會讀取數據分割中的數據 year=2020/month=10/day=01

使用 EXPLAIN 條款並檢查提供的計畫,看看 Delta Lake 是否會自動產生任何分割過濾器。

身份欄位

Important

在 Delta Lake 資料表上宣告身份欄位會使並行交易失效。 只有在不需要同時寫入目標資料表的使用情境中,才使用身份欄位。 詳見 身份欄位限制

Delta Lake 識別數據行是一種產生的數據行類型,可為每個插入數據表的記錄指派唯一值。 下列範例示範在建立數據表語句期間宣告識別數據行的基本語法:

SQL

CREATE TABLE table_name (
  id_col1 BIGINT GENERATED ALWAYS AS IDENTITY,
  id_col2 BIGINT GENERATED ALWAYS AS IDENTITY (START WITH -1 INCREMENT BY 1),
  id_col3 BIGINT GENERATED BY DEFAULT AS IDENTITY,
  id_col4 BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH -1 INCREMENT BY 1)
 )

Python

from delta.tables import DeltaTable, IdentityGenerator
from pyspark.sql.types import LongType

DeltaTable.create()
  .tableName("table_name")
  .addColumn("id_col1", dataType=LongType(), generatedAlwaysAs=IdentityGenerator())
  .addColumn("id_col2", dataType=LongType(), generatedAlwaysAs=IdentityGenerator(start=-1, step=1))
  .addColumn("id_col3", dataType=LongType(), generatedByDefaultAs=IdentityGenerator())
  .addColumn("id_col4", dataType=LongType(), generatedByDefaultAs=IdentityGenerator(start=-1, step=1))
  .execute()

Scala

import io.delta.tables.DeltaTable
import org.apache.spark.sql.types.LongType

DeltaTable.create(spark)
  .tableName("table_name")
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col1")
      .dataType(LongType)
      .generatedAlwaysAsIdentity().build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col2")
      .dataType(LongType)
      .generatedAlwaysAsIdentity(start = -1L, step = 1L).build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col3")
      .dataType(LongType)
      .generatedByDefaultAsIdentity().build())
  .addColumn(
    DeltaTable.columnBuilder(spark, "id_col4")
      .dataType(LongType)
      .generatedByDefaultAsIdentity(start = -1L, step = 1L).build())
  .execute()

備註

適用於身分識別數據行的 Scala 和 Python API 可在 Databricks Runtime 16.0 和更新版本中使用。

若要檢視使用識別資料列建立資料表的所有 SQL 語法選項,請參閱 CREATE TABLE[USING]

您可以選擇性指定下列項目:

  • 起始值。
  • 步驟大小,可以是正數或負數。

起始值與步驟大小預設為 1。 您無法指定步驟大小為0

識別欄位指派的值是唯一且按照指定的步驟方向遞增,以指定的步驟大小倍數遞增,但不保證是連續的。 例如,使用的起始值 0 和的逐步大小 2,所有值都是正偶數,但某些偶數可能會略過。

使用 子句 GENERATED BY DEFAULT AS IDENTITY時,插入作業可以指定標識列的值。 將子句修改為 GENERATED ALWAYS AS IDENTITY 以覆蓋手動設定值的功能。

識別數據行僅支援 BIGINT 類型,如果指派的值超過 所 BIGINT支援的範圍,則作業會失敗。

若要瞭解如何同步處理身份欄位的值與數據,請參閱 ALTER TABLE ... COLUMN 子句

CTAS 和識別欄位

您無法在使用 CREATE TABLE table_name AS SELECT (CTAS) 語句時定義架構、識別資料行條件約束或任何其他資料表規格。

若要建立具有識別數據行的新數據表,並填入現有的數據,請執行下列動作:

  1. 建立具有正確架構的數據表,包括識別數據行定義和其他數據表屬性。
  2. 執行INSERT作業。

下列範例會使用 DEFAULT 關鍵詞來定義識別數據行。 如果插入數據表中的數據包含識別數據行的有效值,則會使用這些值。

CREATE OR REPLACE TABLE new_table (
  id BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 5),
  event_date DATE,
  some_value BIGINT
);

-- Inserts records including existing IDs
INSERT INTO new_table (id, event_date, some_value)
SELECT id, event_date, some_value FROM old_table;

-- Insert records and generate new IDs
INSERT INTO new_table (event_date, some_value)
SELECT event_date, some_value FROM new_records;

識別資料行限制

使用識別資料列時,存在下列限制:

  • 已啟用識別數據行的數據表不支援並行交易。
  • 你不能使用識別欄位來分割資料表。
  • 你不能使用 ALTER TABLEADDREPLACECHANGE 身份欄位。
  • 你無法更新現有紀錄的身份欄位值。

備註

若要變更 IDENTITY 現有記錄的值,您必須刪除記錄,並將 INSERT 它刪除為新記錄。

生成的欄位與欄位遮罩

產生的欄位無法參考已套用欄位遮罩的欄位,因為產生的值會揭露遮罩所保護的底層資料。 這會產生錯誤,查詢失敗。 請參閱 行篩選和列遮罩

以下是錯誤的例子:

要解決所有這些錯誤,你必須重新設計表格,讓產生的欄位和遮罩欄位不會重疊。