在 Azure Databricks 上複製數據表
您可以使用 命令,在特定版本 clone
在 Azure Databricks 上建立現有 Delta Lake 數據表的複本。 複製可以是深或淺層。
Azure Databricks 也支持複製 Parquet 和 Iceberg 數據表。 請參閱 以累加方式將 Parquet 和 Iceberg 數據表複製到 Delta Lake。
如需搭配 Unity 目錄使用複製的詳細資訊,請參閱 Unity 目錄數據表的淺層複製。
注意
Databricks 建議使用 Delta Sharing 來提供跨不同組織之數據表的只讀存取權。 請參閱什麼是 Delta Sharing?。
複製類型
- 深層複製是複製品,除了現有數據表的元數據之外,也會將源數據表數據複製到複製目標。 此外,也會複製數據流元數據,讓寫入 Delta 數據表的數據流可以在源數據表上停止,並在複製的目標上繼續從該複製區離開的位置繼續。
- 淺層複製是不會將資料檔複製目標的複製品。 數據表元數據相當於來源。 這些複製品的建立成本更低。
複製的元數據包括:架構、數據分割資訊、不變性、可為 Null 性。 針對僅限深層複製,也會複製數據流和 COPY INTO 元數據。 未複製的元數據是數據表描述和 使用者定義的認可元數據。
Delta 複製作業的語意為何?
如果您已使用已向Hive中繼存放區註冊的 Delta 數據表,或未註冊為數據表的檔案集合,則複製具有下列語意:
重要
在 Databricks Runtime 13.3 LTS 和更新版本中,Unity 目錄受控數據表支持淺層複製。 Unity 目錄數據表的複製語意與其他環境中的 Delta Lake 複製語意有很大的不同。 請參閱<Unity 目錄資料表>的淺複製。
- 對深層或淺層複製所做的任何變更只會影響複製本身,而不會影響源數據表。
- 淺層複製來源目錄中的參考數據檔。 如果您在來源資料表上執行
vacuum
,客戶端就無法再讀取參考的資料檔,而且FileNotFoundException
會擲回 。 在此情況下,執行複製以 取代淺層複製會修復複製品。 如果這種情況經常發生,請考慮改用不相依於源數據表的深層複製。 - 深層複製不取決於複製來源,但建立成本很高,因為深層複製會複製數據和元數據。
- 如果
replace
該路徑上沒有數據表,請使用 複製到已經有數據表的目標,如果在該路徑上不存在,則會建立 Delta 記錄檔。 您可以執行vacuum
來清除任何現有的數據。 - 針對現有的 Delta 數據表,會建立新的認可,其中包含源數據表的新元數據和新數據。 這個新的認可是累加的,這表示只有自上次複製之後的新變更會認可至數據表。
- 複製數據表與 或
CTAS
不同Create Table As Select
。 複製除了數據之外,也會複製源數據表的元數據。 複製也有更簡單的語法:您不需要指定從源數據表取得數據分割、格式、不因變數、可為 Null 等。 - 複製的數據表具有其源數據表的獨立歷程記錄。 複製數據表上的時間移動查詢不適用於其源數據表上的相同輸入。
範例複製語法
下列程式代碼範例示範如何建立深層和淺層複製的語法:
SQL
CREATE TABLE target_table CLONE source_table; -- Create a deep clone of source_table as target_table
CREATE OR REPLACE TABLE target_table CLONE source_table; -- Replace the target
CREATE TABLE IF NOT EXISTS target_table CLONE source_table; -- No-op if the target table exists
CREATE TABLE target_table SHALLOW CLONE source_table;
CREATE TABLE target_table SHALLOW CLONE source_table VERSION AS OF version;
CREATE TABLE target_table SHALLOW CLONE source_table TIMESTAMP AS OF timestamp_expression; -- timestamp can be like “2019-01-01” or like date_sub(current_date(), 1)
Python
from delta.tables import *
deltaTable = DeltaTable.forName(spark, "source_table")
deltaTable.clone(target="target_table", isShallow=True, replace=False) # clone the source at latest version
deltaTable.cloneAtVersion(version=1, target="target_table", isShallow=True, replace=False) # clone the source at a specific version
# clone the source at a specific timestamp such as timestamp="2019-01-01"
deltaTable.cloneAtTimestamp(timestamp="2019-01-01", target="target_table", isShallow=True, replace=False)
Scala
import io.delta.tables._
val deltaTable = DeltaTable.forName(spark, "source_table")
deltaTable.clone(target="target_table", isShallow=true, replace=false) // clone the source at latest version
deltaTable.cloneAtVersion(version=1, target="target_table", isShallow=true, replace=false) // clone the source at a specific version
deltaTable.cloneAtTimestamp(timestamp="2019-01-01", target="target_table", isShallow=true, replace=false) // clone the source at a specific timestamp
如需語法詳細數據,請參閱 CREATE TABLE CLONE。
複製計量
CLONE
在作業完成之後,會將下列計量報告為單一數據列 DataFrame:
source_table_size
:以位元組為單位複製之源數據表的大小。source_num_of_files
:源數據表中的檔案數目。num_removed_files
:如果要取代數據表,則會從目前的數據表中移除多少個檔案。num_copied_files
:從來源複製的檔案數目(淺層複製的 0 個)。removed_files_size
:從目前數據表中移除之檔案的位元元組大小。copied_files_size
:將檔案複製到數據表的位元組大小。
權限
您必須設定 Azure Databricks 資料表存取控制和雲端提供者的許可權。
資料表存取控制
深層和淺層複製需要下列許可權:
SELECT
源數據表的許可權。- 如果您使用
CLONE
來建立新的資料表,CREATE
您要在其中建立數據表的資料庫許可權。 - 如果您使用
CLONE
來取代數據表,則必須擁有MODIFY
數據表的許可權。
雲端提供者許可權
如果您已建立深層複製,讀取深層複製的任何使用者都必須具有複製目錄的讀取許可權。 若要變更複製品,用戶必須具有複製目錄的寫入許可權。
如果您已建立淺層複製,讀取淺層複製的任何使用者都需要許可權才能讀取原始數據表中的檔案,因為數據檔會保留在具有淺層複製的源數據表中,以及複製者的目錄。 若要變更複製品,使用者將需要複製目錄的寫入許可權。
使用複製進行數據封存
您可以使用深層複製來保留某個時間點的數據表狀態,以供封存之用。 您可以累加同步深層複製,以維護源數據表的更新狀態以進行災害復原。
-- Every month run
CREATE OR REPLACE TABLE archive_table CLONE my_prod_table
使用複製 ML 模型複製
執行機器學習時,您可能會想要封存您定型 ML 模型的特定資料表版本。 未來的模型可以使用這個封存的數據集進行測試。
-- Trained model on version 15 of Delta table
CREATE TABLE model_dataset CLONE entire_dataset VERSION AS OF 15
在生產數據表上使用複製進行短期實驗
若要在生產數據表上測試工作流程而不損毀數據表,您可以輕鬆地建立淺層複製。 這可讓您在包含所有生產數據的複製數據表上執行任意工作流程,但不會影響任何生產工作負載。
-- Perform shallow clone
CREATE OR REPLACE TABLE my_test SHALLOW CLONE my_prod_table;
UPDATE my_test WHERE user_id is null SET invalid=true;
-- Run a bunch of validations. Once happy:
-- This should leverage the update information in the clone to prune to only
-- changed files in the clone if possible
MERGE INTO my_prod_table
USING my_test
ON my_test.user_id <=> my_prod_table.user_id
WHEN MATCHED AND my_test.user_id is null THEN UPDATE *;
DROP TABLE my_test;
使用複製覆寫數據表屬性
資料表屬性覆寫特別適用於:
- 在與不同業務單位共享數據時,以擁有者或使用者資訊標註數據表。
- 需要封存差異數據表和數據表歷程記錄或時間移動。 您可以個別指定封存資料表的數據和記錄保留期間。 例如:
SQL
CREATE OR REPLACE TABLE archive_table CLONE prod.my_table
TBLPROPERTIES (
delta.logRetentionDuration = '3650 days',
delta.deletedFileRetentionDuration = '3650 days'
)
Python
dt = DeltaTable.forName(spark, "prod.my_table")
tblProps = {
"delta.logRetentionDuration": "3650 days",
"delta.deletedFileRetentionDuration": "3650 days"
}
dt.clone(target="archive_table", isShallow=False, replace=True, tblProps)
Scala
val dt = DeltaTable.forName(spark, "prod.my_table")
val tblProps = Map(
"delta.logRetentionDuration" -> "3650 days",
"delta.deletedFileRetentionDuration" -> "3650 days"
)
dt.clone(target="archive_table", isShallow = false, replace = true, properties = tblProps)