在 Azure Databricks 上複製數據表
您可以使用 clone
命令,在 Azure Databricks 上的特定版本中建立現有 Delta Lake 資料表的副本。 複製可以是深或淺層。
Azure Databricks 也支持複製 Parquet 和 Iceberg 數據表。 請參閱 以累加方式將 Parquet 和 Iceberg 數據表複製到 Delta Lake。
如需有關使用 Unity Catalog 的克隆的詳細資訊,請參閱 Unity Catalog 表的淺層克隆。
注意
Databricks 建議使用 Delta Sharing 來提供跨不同組織之數據表的只讀存取權。 請參閱什麼是 Delta Sharing?。
複製類型
- 深層複製是複製品,除了現有數據表的元數據之外,也會將源數據表數據複製到複製目標。 此外,也會複製資料流的元數據,讓寫入 Delta 資料表的資料流可以在源資料表上停止,並在克隆的目標表上從中斷處繼續。
- 淺層複製是一種不將資料檔案複製到目標的複製品。 數據表元數據相當於來源。 這些複製品的建立成本更低。
複製的元數據包括:結構、分區資訊、不變條件、空值屬性。 僅在進行深層複製時,數據流和 COPY INTO
元數據也會被複製。 未複製的元數據是數據表描述和使用者定義的認可元數據。
Delta 複製作業的語意為何?
如果您使用登錄至 Hive 中繼存放區的 Delta 數據表或未註冊為資料表的檔案集合,則複製具有下列語意:
重要
在 Databricks Runtime 13.3 LTS 和更高版本中,Unity Catalog 內受管控的資料表支援淺層複製。 Unity 目錄數據表的複製語意與其他環境中的 Delta Lake 複製語意有很大的不同。 請參閱Unity Catalog 資料表的淺層複製。
- 對深層或淺層複製所做的任何變更只會影響複製本身,而不會影響源數據表。
- 淺層複本會引用來源目錄中的數據檔案。 如果您在來源資料表上執行
vacuum
,客戶端就無法再讀取參考的資料檔,而且FileNotFoundException
會擲回 。 在此情況下,執行複製以 取代淺層複製會修復複製品。 如果這種情況經常發生,請考慮改用不相依於源數據表的深層複製。 - 深層複製不取決於複製來源,但建立成本很高,因為深層複製會複製數據和元數據。
- 如果使用
replace
複製到已經有資料表的目標路徑,而該路徑上還不存在 Delta 記錄檔,則會建立一個新的 Delta 記錄檔。 您可以執行vacuum
來清除任何現有的數據。 - 針對現有的 Delta 資料表,會建立新的提交,其中包含來自源資料表的新元數據和新數據。 這個新的提交是增量的,這表示只有自上次複製以來的新變更會提交到數據表中。
- 複製數據表與
Create Table As Select
或CTAS
並不相同。 克隆會複製源資料表的元數據以及數據。 複製也有更簡單的語法:您不需要指定分區、格式、不變性、允許為 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;
使用克隆覆寫數據表屬性
資料表屬性覆寫特別適用於:
- 在與不同業務單位共享數據時,以擁有者或使用者資訊標註數據表。
- 需要封存 Delta 表和表的歷史記錄或時間旅行。 您可以個別指定封存資料表的數據和記錄保留期間。 例如:
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)