datainfra前沿动态 · Vol.48

Databricks AUTO CDC 增强版实现双轴历史追踪让审计存续于 VACUUM 之后;Apache Iceberg v3 引入 Variant 半结构化类型;DuckDB 创始人 Hannes Muhleisen 反思行业误诊 SQL 十余年

本期聚焦三条 DataInfra 动态:Databricks 将 AUTO CDC 提升到下一阶段,引入 Bitemporal AUTO CDC(业务时间+系统时间双轴历史追踪),用 STORED AS BITEMPORAL 声明式解决 SEC Rule 17a-4/FINRA 审计合规与乱序事件重写历史难题,并将 Partial Updates 转正 GA、把 AUTO CDC Type 1 Python API 贡献给开源 Apache Spark 4.2;Apache Iceberg v3 spec 新增 Variant 半结构化类型,采用 Apache Parquet 的 VARIANT(1) 编码统一存储异构 JSON 式文档,保留 date/timestamp/decimal 等原生类型;DuckDB 创始人 Hannes Muhleisen 在邮件访谈中反思行业十余年前'误诊'了 SQL——开发者厌恶的从来不是语言,而是安装、服务器与客户端协议,并透露一个未宣布的 DuckDB 新发布预计今年推出。

DataInfra Databricks AUTO CDC Bitemporal 双轴历史 SCD Type 2 SEC Rule 17a-4 FINRA Partial Updates Spark Declarative Pipelines Apache Spark 4.2 Time Travel VACUUM Apache Iceberg Variant 半结构化数据 Parquet Iceberg v3 Spark 4.0 Flink 2.1 DuckDB Hannes Muhleisen 单机分析 SQL

本期追踪到三条 DataInfra 动态,从声明式变更捕获、半结构化数据存储到单机分析哲学的重新审视,共同指向一个正在发酵的信号:数据基础设施正在从”为长尾集群而建”转向”为真实的工作负载形态而建”——而后者远比我们想象得更简单、更异构。2026 年 8 月 11 日,Databricks 发布 AUTO CDC 增强版,引入 Bitemporal AUTO CDC(业务时间 + 系统时间的双轴历史追踪),用一句 STORED AS BITEMPORAL 声明替代数百行脆弱的 MERGE 逻辑,同时解决 SEC Rule 17a-4/FINRA 的审计合规与乱序事件重写历史的难题——更重要的是,它将历史存为数据行而非文件版本,让可复现性真正存活于 VACUUM 之后。Apache Iceberg 则在 v3 spec 中正式纳入 Variant 半结构化类型,采用 Apache Parquet 的 VARIANT(1) 编码,让异构 JSON 式文档在保留 date/timestamp/decimal 原生类型的前提下共存于同一列,终结了”JSON 当字符串存”与”宽表扁平化”之间的两难。而 DuckDB 创始人 Hannes Muhleisen 在一场邮件访谈中抛出一个尖锐的行业反思:十余年前业界”误诊”了 SQL——2013 年开发者真正厌恶的不是语言本身,而是安装、服务器与客户端协议,Snowflake 与 Amazon 公开的工作负载轨迹显示真正需要集群的分析查询只占极小比例,而数据库行业却花了二十年为这条长尾而建。三条动态分别触及声明式可复现性、半结构化存储、单机分析哲学三个维度,恰好构成了一幅 DataInfra 正在”回归简单、回归真实负载”的完整侧写。


Databricks AUTO CDC 增强版:双轴历史追踪让审计合规与可复现性”存活于 VACUUM 之后”

事件概述

2026 年 8 月 11 日,Databricks 发布博客《Taking AUTO CDC to the next level: Solving the hardest real-world use cases》,作者为 Josh Seidel、Shanelle Roman 与 Sudhanva Huruli。这是对早前”Stop hand-coding change data capture pipelines”一文的延续——AUTO CDC 已在 Apache Spark Declarative Pipelines(SDP)中通过声明式方式自动化了 SCD Type 1、SCD Type 2 与 Snapshot CDC,用几句声明替代了数百行手写 MERGE 逻辑。此次升级直面三类标准 CDC 模式难以解决的现实挑战:乱序的双时态时间线、部分记录更新(NULL 会误覆盖现有数据)、以及”存续于存储保留窗口之外的审计能力”,并将相关能力扩展到开源 Apache Spark 4.2。

技术解析

  • Bitemporal AUTO CDC 双轴历史追踪:标准 SCD Type 2 只能回答”事实何时在真实世界发生变化”,却无法回答”你的系统在某一时点相信什么”。Bitemporal 模式独立追踪两条时间线——业务时间(business time)(事实在真实世界为真的时刻,如股票代码周一生效)与系统时间(system time)(系统何时得知该数据,周一的变更可能周三才进入管道)。每张目标表自动获得四个系统管理列:__START_AT、__END_AT(业务时间)与 __SYSTEM_START_AT、__SYSTEM_END_AT(系统时间)。一个逻辑事实可对应多条物理行(每个业务版本 × 系统版本组合),使沿任一轴的时点重建成为可能。

  • 乱序事件的历史重写:核心行为保证是”事件可以以任意顺序在任一时间线上到达”。当一条带更早业务时间或系统时间的更正记录到达时,引擎会重写受影响的历史区间而非简单追加到末尾。SQL 语法为 STORED AS BITEMPORAL + SEQUENCE BY business_time + SYSTEM SEQUENCE BY system_time(注意不是 SCD TYPE BITEMPORAL)。排序列必须是可排序类型且不含 NULL 排序值;该功能目前处于 Beta,需将管道固定到 channel: PREVIEW,运行在 serverless SDP 或 Pro/Advanced 版本。

  • 超越 Time Travel:可复现性存活于 VACUUM 之后:模型训练的可复现性需要数月后仍能重建训练所用数据集。Delta Lake Time Travel 依赖表的文件历史,一旦 VACUUM 越过默认 7 天保留窗口删除了旧文件,训练时记录的 TIMESTAMP AS OF 就会悄悄失效。而双时态表把历史存为数据行而非文件版本——VACUUM 与 OPTIMIZE 只压缩文件、永不触碰逻辑历史,因此每个过去的业务/系统版本仍是可查询的行。做法是把两个 as-of 时刻(业务时间 + 系统时间)作为 MLflow 参数记录,训练查询即可在日后精确重建”当时系统所相信的状态”。

  • Partial Updates 转正 GA:许多 CDC 源只发送变更字段、其余字段填 NULL。Partial Updates 允许更新事件只修改列子集,对选中列而言,入站更新中的 NULL 被解释为”不更新”而非覆盖。以目标行 (1, 'A', 20) 与入站 (1, NULL, 30) 为例,默认 AUTO CDC 会把行改成 (1, NULL, 30),开启 Partial Updates 后 name 的 NULL 被忽略,结果为 (1, 'A', 30)。启用只需在 AUTO CDC 定义中加一个参数,三种写法:IGNORE NULL UPDATES ON columnList、IGNORE NULL UPDATES ON * EXCEPT (columnList)、以及逐行不同的源列名 COLUMNS TO UPDATE。

  • 开源贡献路径:Databricks 将 AUTO CDC Type 1 的 Python API 按 Spark 的常规演进方式(评审提案 + PR,而非一次性代码投放)贡献给 Apache Spark 4.2(见 SPIP 与 SPARK-56249)。乱序数据的正确性内建:一个辅助小表跟踪来自早到事件的删除墓碑状态,重试的微批会收敛而非破坏目标表;因其构建在 Spark 的流式与表抽象之上而非存储格式,可同时运行在 Delta Lake 与 Apache Iceberg 上。SQL 接口 CREATE FLOW ... AS AUTO CDC INTO 已合入 master,将在下一版 Apache Spark 发布。

行业影响

这条动态的深层意义在于:CDC 与审计合规正在从”手写胶水代码”变成”声明式基础设施能力”。SEC 自 2021 年以来的记录保存执法行动已在 100+ 家公司身上罚出超 20 亿美元,而”数月后回答参考数据在报告日说了什么、系统当时信了什么”这类问题,恰恰是传统 SCD Type 2 与基于文件版本的 Time Travel 都无法稳健回答的。双时态历史以”数据行”形态存续,从根本上绕开了 VACUUM 带来的可复现性陷阱,把合规与 ML 可复现性的契约简化为 MLflow 里的一对时间戳。对数据工程团队而言,这意味着不再需要为 SEC Rule 17a-4 / FINRA 场景自研一套脆弱的位时态框架。

相关链接


Apache Iceberg v3 引入 Variant 半结构化类型:异构 JSON 文档与原生类型在同一列共存

事件概述

Apache Iceberg 官方博客发布《Semi-Structured Data in Apache Iceberg: Meet the Variant Type》,宣布 Iceberg v3 spec 新增 Variant 类型,专为”字段逐行不同的 JSON 式半结构化数据”设计。这是 Variant 系列文章的第一篇,覆盖 Variant 是什么、为何存在、如何融入 Iceberg 表;下一篇将介绍 shredding(将高频访问字段转存为类型化列的技术)。Variant 存储于 Parquet、Avro、ORC 三种格式,而 shredding 目前仅支持 Parquet。

技术解析

  • Variant 解决的问题:传统处理半结构化数据有两条路,各有缺陷——JSON 当字符串存(灵活,但读单个字段要解析整段文本,且 JSON 类型系统薄弱:timestamp 只是字符串、数字精度含糊)与刚性扁平化 schema(查询快,但每个新字段都是一次 schema 迁移,稀疏字段浪费空间)。Variant 兼具 JSON 的灵活性与紧凑的类型化二进制存储:值保留原生类型(date/timestamp/timestamptz/binary/decimal 不再坍缩成 JSON 的字符串与数字),字段名收进字典按 id 引用、无需反复写出全名,且无需预先声明 schema——不同形状的文档共存于同一列,新字段零迁移。

  • 在 Iceberg 类型系统中的位置:Variant 在 v3 spec 中自成一类——“既非 primitive 也非 nested”,比 primitive 更丰富,却又不像 struct/list 那样有固定声明形状。它支持嵌套:Variant array(有序、元素类型不受单一类型约束)与 Variant object(字符串键的字段集合、值同为 Variant、字段集不固定)。

  • 存储编码(复用 Parquet 而非自定义):Iceberg 没有自定义二进制编码,而是直接采用 Apache Parquet 项目的 Variant 编码,因此一个 variant 列映射为 Parquet 的 group,含两个 binary 字段:metadata(字段名字典,value 里的名字用整数 id 引用)与 value(编码后的标量/数组/对象;数组与对象存储每个元素的 field_offset 字节偏移,对象额外存 field_id 指向 metadata 字典)。Variant 列本身按字段 ID 寻址(与其他 Iceberg 列一致),但其 metadata/value 子字段按名访问——这一点对 shredding 至关重要。

  • 跨引擎读写:Apache Spark 4.0/4.1 可创建含 VARIANT 列的表并读写(读取在 Iceberg 1.10.0 落地于 Spark 4.0;Iceberg 1.11.0 增加 Spark 4.1 及 shredded Variant 写入);Apache Flink 2.1 在 Iceberg 1.11.0 增加 Variant 支持(仅 unshredded,shredded 写入已合入、预计后续版本发布)。因各引擎共用同一 Iceberg Variant 类型,一个引擎写入的值在另一引擎读回保持一致。

  • 查询方式:Variant 列要求表为 format version 3(TBLPROPERTIES('format-version'='3')),写入用 parse_json(...),读取用 variant_get(column, path, type) 提取路径字段,缺字段处返回 null。适合事件/点击流、结构化异构日志、IoT 传感器遥测、第三方 API/webhook 响应(schema 归别人所有且随时可变)、以及本会变成”全 NULL 宽表”的稀疏属性。Variant 不是已知 schema 的替代品——稳定且常查的字段应保持普通类型列,常见模式是”稳定字段独立列 + 可变部分塞进单个 Variant 列”。

行业影响

Iceberg Variant 的意义在于为 Lakehouse 补齐了”半结构化数据”这块长期由 JSON 字符串和宽表两种劣质方案拼凑的拼图。其关键设计选择——复用 Parquet 的 Variant 编码而非自创格式——保证了 Spark、Flink 等引擎在开放表格式内的读写一致性,也与 Databricks Delta 的 Variant 思路形成事实上的编码对齐。而 shredding(下一步)才是真正的性能兑现点:把高频字段转成类型化 Parquet 列,让查询只读所需列、并恢复 per-field min/max 统计做数据剪枝,弥补”整份文档塞进单个 value 列”导致的统计剪枝缺失。对数据平台而言,这意味着”先落异构事件、再按访问模式逐步 shredding”成为一条比”先设计刚性 schema”更务实的演进路径。

相关链接


DuckDB 创始人 Hannes Muhleisen 反思:行业十余年前”误诊”了 SQL,真正需要集群的查询只占极小比例

事件概述

在 Lets Data Science 近期发布的一封邮件访谈中,DuckDB 创始人、DuckDB Labs CEO Hannes Muhleisen 抛出一个尖锐的行业反思:十年前业界”误诊”了 SQL。他的核心论点是——2013 年开发者真正厌恶的从来不是 SQL 语言本身,而是随之而来的安装、服务器与客户端协议;那些替换掉 SQL 的 NoSQL 系统,最终又长回了”SQL 形状”的东西,却少了四十年的工程经验积累。访谈中他还透露,一个尚未宣布的 DuckDB 新发布预计今年推出。

技术解析

  • 对”NoSQL 取代 SQL”叙事的重估:Muhleisen 指出,把 2013 年开发者对 SQL 的抱怨归因于”语言不好用”是误诊。真正让开发者痛苦的,是数据库的运维负担——安装、起服务器、维护客户端协议。当 NoSQL 系统绕开这套负担迅速流行后,为了表达查询,它们又慢慢长回了类似 SQL 的东西,只是缺少了关系数据库四十年的成熟经验。

  • “集群需求被严重高估”的数据依据:他援引 Snowflake 与 Amazon 公开的工作负载轨迹,称其中只有极小比例的分析查询真正需要集群(“a fraction of a percent”)。而数据库行业在过去二十年里,恰恰是围绕这条”长尾”——需要横向扩展集群的极少数极端场景——来构建的,导致单机本可轻松消化的绝大多数分析负载,被过度工程化了。

  • 浏览器内分析应运行”同一引擎”而非玩具版本:Muhleisen 主张,在浏览器内做分析时,用户应运行与服务器端相同的 DuckDB 引擎(得益于 WASM 移植),而不是一个功能缩水的”玩具版”。这与 DuckDB 一贯的”进程内分析数据库”理念一脉相承,也呼应了此前 DuckDB v2.0 规划中异步 I/O、Quack 协议等方向。

  • 未宣布的新发布预告:访谈确认了一个尚未公开的 DuckDB 发布预期今年推出(“an unannounced DuckDB launch expected this year”),但未披露具体细节。

行业影响

这条动态的价值不在某个具体版本号,而在于它提供了一个与”云原生、大规模集群”主流叙事相对照的认知锚点。Muhleisen 的论点(与近年 DuckDB、MotherDuck、乃至 Databricks 收购 Electric 后把 Postgres 推到 Agent 沙箱边缘端的动向相互印证)共同指向一个趋势:数据基础设施正在重新发现”单机 + 进程内”这一被集群叙事长期遮蔽的形态。对数据团队而言,这是一个务实的提醒——在默认上马分布式集群之前,先用公开的工作负载数据问一句”我的查询究竟需不需要集群”,可能省下大量不必要的运维与成本。而 DuckDB 今年未宣布的新发布,则值得作为后续追踪的悬念。

相关链接


编者评

本期三条动态看似分属三个不同层面——Databricks 的声明式 CDC、Iceberg 的半结构化类型、DuckDB 的单机分析哲学——但把它们并置阅读,能看出一个清晰的共同底色:DataInfra 正在从”为极端场景而过度设计”回归”为真实负载形态而设计”。Databricks 用一句 STORED AS BITEMPORAL 把过去需要自研位时态框架的合规难题变成声明式能力,Iceberg 用复用 Parquet 编码的 Variant 终结了 JSON 字符串与宽表的二选一,而 Muhleisen 则用 Snowflake/Amazon 的公开轨迹数据提醒我们:集群是长尾,不是常态。三者的共同逻辑是降低”正确做事”的门槛——合规不必手写 MERGE、异构数据不必预设 schema、单机分析不必强上集群。值得留意的是,Databricks AUTO CDC 的开源路径(Python API 先入 Spark 4.2、SQL 接口已合 master)与 Iceberg Variant 的 shredding 后续,都还在演进中;而 DuckDB 今年那个”未宣布的新发布”,将是接下来几期值得持续追踪的一条暗线。跨厂商的观察视角依旧是本期想强调的:开放表格式(Iceberg/Delta)在 Variant 编码上的事实对齐、以及”进程内/单机”形态的回归,都不是某一家厂商的孤立动作,而是整个数据基础设施在 Agentic AI 与成本压力双重驱动下的结构性转向。