克隆 Azure Databricks 上的表
可以使用 clone
命令创建特定版本的 Azure Databricks 上现有 Delta Lake 表的副本。 克隆可以是深层克隆,也可是浅表克隆。
Azure Databricks 还支持克隆 Parquet 和 Iceberg 表。 请参阅将 Parquet 和 Iceberg 表增量克隆到 Delta Lake。
有关将克隆与 Unity Catalog 结合使用的详细信息,请参阅 Unity Catalog 表的浅表克隆。
注意
Databricks 建议使用增量共享来提供对不同组织中表的只读访问权限。 请参阅什么是 Delta Sharing?。
克隆类型
- 除了复制现有表的元数据,深层克隆还会将源表数据复制到克隆目标。 此外,它还会克隆流元数据,使写入 Delta 表的流可在源表上停止,并在克隆的目标位置(即停止位置)继续进行克隆。
- 浅表克隆不会将数据文件复制到克隆目标。 表元数据等效于源。 创建这些克隆的成本较低。
克隆的元数据包括:架构、分区信息、不变性、为 Null 性。 深层克隆还会克隆流和 COPY INTO 元数据(浅表克隆不克隆这些内容)。 未克隆的两种元数据是表说明和用户定义的提交元数据这。
Delta 克隆操作的语义是什么?
如果已使用注册到 Hive 元存储的 Delta 表或未注册为表的文件集合,则克隆具有以下语义:
重要
在 Databricks Runtime 13.3 LTS 及更高版本中,Unity Catalog 托管表支持浅表克隆。 Unity Catalog 表的克隆语义与其他环境中的 Delta Lake 克隆语义明显不同。 请参阅适用于 Unity Catalog 表的浅表克隆。
- 对深层克隆或浅表克隆所做的任何更改都只影响克隆本身,不会影响源表。
- 浅表克隆会引用源目录中的数据文件。 如果对源表运行
vacuum
,则客户端不再读取引用的数据文件,并且会引发FileNotFoundException
。 在这种情况下,在浅表克隆上运行带有 replace 的克隆可修复该克隆。 如果此情况经常发生,请考虑使用深层克隆,而不是依赖于源表。 - 深层克隆不依赖进行克隆的源,但由于深层克隆会复制数据和元数据,因此创建成本很高。
- 使用
replace
克隆到已在该路径具有表的目标时,如果该路径不存在,会创建一个 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
在操作完成后以单行数据帧的形式报告以下指标:
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)