Azure Databricks 上的 Delta Lake 支持两个隔离级别,这些隔离级别控制给定表上的并发操作的交互方式:
| 隔离级别 | 说明 |
|---|---|
| 序列 化 | 最强隔离级别。 确保已提交的写入操作和所有读取都是 可序列化的。 只要有一个串行序列,就允许执行一次操作,从而生成与表中所示相同的结果。 对于写入操作,此串行序列与表历史记录中看到的顺序相同。 |
| WriteSerializable (默认) | 比 Serializable 更弱的隔离级别。 确保仅写入操作(而非读取操作)是可序列化的。 这仍然比 快照 隔离更强。 为最常见的操作提供数据一致性和可用性的良好平衡。 |
隔离级别如何影响读取
读取操作始终使用快照隔离。 写入隔离级别决定读取器是否可以看到根据历史记录“从未存在”过的表快照。
- 可序列化:读取器始终只看到符合历史记录的表
- WriteSerializable:读取器可能会看到 Delta log 中并不存在的表状态
示例:并发删除和插入
考虑如下场景:一个长时间运行的删除事务和一个插入事务同时启动,并且都读取版本 v0。 插入事务首先提交并创建版本 v1。 之后,删除事务尝试提交 v2:
t0: deleteTxn_START
t1: insertTxn_START
t2: insertTxn_COMMIT(v1)
t3: deleteTxn_COMMIT(v2)
在此方案中, deleteTxn 看不到插入 insertTxn 的数据,也没有删除它们:
-
Serializable:不允许
deleteTxn提交,并发生冲突 -
WriteSerializable:允许
deleteTxn提交,因为事务可以排序。 生成的表状态就像insertTxn发生在deleteTxn之后一样,因此插入的行成为表的一部分。 但是,Delta 历史记录显示物理提交顺序(v1 处的insertTxn在 v2 处的deleteTxn之前)。
设置隔离级别
使用 ALTER TABLE 以下命令设置隔离级别:
ALTER TABLE <table-name> SET TBLPROPERTIES ('delta.isolationLevel' = <level-name>)
其中 <level-name> 是 Serializable 或 WriteSerializable。
Example:
-- Change from default WriteSerializable to Serializable
ALTER TABLE my_table SET TBLPROPERTIES ('delta.isolationLevel' = 'Serializable')
Delta Lake 何时提交而不读取表?
如果满足以下条件,Delta Lake INSERT 或追加操作在提交之前不会读取表状态:
- 逻辑可以通过
INSERTSQL 逻辑或追加模式来表示 - 逻辑不包含引用写入操作目标表的子查询或条件
与其他提交一样,Delta Lake 使用事务日志元数据在提交时验证和解析表版本,但实际上不会读取该表的版本。
注释
许多常见模式使用 MERGE 操作来根据表条件插入数据。 尽管可以使用 INSERT 语句重写此逻辑,但如果任何条件表达式引用目标表中的某一列,则这些语句要遵守与 MERGE 相同的并行限制。