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)定義的四個資料分割欄位,其型別col為TIMESTAMP。 -
SUBSTRING(col, pos, len)且的類型col為STRING -
DATE_FORMAT(col, format)和col的類型是TIMESTAMP。- 您只能搭配下列模式使用日期格式:
yyyy-MM和yyyy-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) 語句時定義架構、識別資料行條件約束或任何其他資料表規格。
若要建立具有識別數據行的新數據表,並填入現有的數據,請執行下列動作:
- 建立具有正確架構的數據表,包括識別數據行定義和其他數據表屬性。
- 執行
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 TABLE、ADD或REPLACECHANGE身份欄位。 - 你無法更新現有紀錄的身份欄位值。
備註
若要變更 IDENTITY 現有記錄的值,您必須刪除記錄,並將 INSERT 它刪除為新記錄。
生成的欄位與欄位遮罩
產生的欄位無法參考已套用欄位遮罩的欄位,因為產生的值會揭露遮罩所保護的底層資料。 這會產生錯誤,查詢失敗。 請參閱 行篩選和列遮罩。
以下是錯誤的例子:
你無法建立一個生成欄位,其運算式會參考遮罩欄位。 加薪 COLUMN_MASKS_GENERATED_COLUMN_UNSUPPORTED。
CREATE TABLE tbl ( a INT MASK masking_function, generated_col INT GENERATED ALWAYS AS (a + 1) ) USING DELTA;你不能對已被生成欄位參考的欄位套用欄位遮罩。 觸發 COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN.ADD_MASK。
CREATE TABLE tbl ( a INT, generated_col INT GENERATED ALWAYS AS (a + 1) ) USING DELTA; ALTER TABLE tbl ALTER COLUMN a SET MASK masking_function;從已產生的欄位參考遮罩欄位的資料表讀取也會被阻擋。 加注 COLUMN_MASKS_REFERENCED_BY_GENERATED_COLUMN。READ_BLOCKED。
要解決所有這些錯誤,你必須重新設計表格,讓產生的欄位和遮罩欄位不會重疊。