小林在镇上开了家杂货铺,生意越做越大,分店开到了邻市。总部大刘是数据工程师,他要把所有分店的销售数据统一收进总部仓库。第一次迁数据时,大刘说:“这就像搬家——把所有货架上的商品装箱、装车、运到新仓库,一件不落。”可每月这么搬一次,货车租金和人力成本高得吓人。后来大刘换了法子:“以后每天只把新到的货和卖掉的货记下来,用快递单送过去,不用再把整个仓库翻一遍。”这就是全量同步与增量同步的区别:一个简单粗暴但费时费力,一个轻快灵巧但依赖“变更情报”。本文要用“搬家”与“快递”这对生活搭档,带你搞懂ETL同步策略的选型、陷阱与工程落地。
掌握增量和全量同步策略,是数据工程师设计高效ETL链路的看家本领。你不需要每次都“搬整座仓库”,只需知道什么时候用卡车、什么时候让快递员跑腿——这决定了数据管道的成本、延迟与稳定。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
全量同步原理
小林的第一家分店开张后,大刘要把他三个店的Excel汇总到总部数据库。大刘说:“这最简单,就叫全量同步——像搬家公司一样,把每个仓库的货架全搬空,装车运到总部,再按原样摆好。”小林问:“那要搬多久?”大刘指着报表说:“你看,每个店几万行数据,三个店加起来约100GB,以每秒50MB的传输速度,光搬运就要半小时。”全量同步的魅力正在于此:逻辑简单,不需要任何“情报”,只要把整张表拷贝过去,数据一定完整。
所谓全量快照,就是某时刻整张表的完整副本。实现上通常先清空目标表(TRUNCATE),再逐行插入(INSERT),或者直接用数据库自带的导出导入工具。它的优点是绝对可靠,缺点也直白:数据量越大,耗时越长,而且拷贝期间源表往往要加锁,业务写入会被阻塞。因此全量同步只适合小表初始化或低频兜底,比如维表、配置表,或数据仓库分层中的首次灌数。
搬完家后,小林发现仓库门口堆满了箱子,员工要重新整理上架,期间新订单也没法正常处理。全量同步就是这样一个“大动干戈”的糙汉子:可靠,但每次都要兴师动众。所以它适合一年搬一次家,不适合天天搬家。
- 总耗时构成全量同步总时间由传输时间和锁表时间两部分叠加而成。
- 数据体积V 代表待拷贝的数据总量,单位通常取 GB,由行数与每行大小乘积决定。
- 传输速率R 是网络或导出工具单位时间传送的数据量,瓶颈常在磁盘 I/O 或带宽。
- 锁表代价全量拷贝时源表可能被锁定,期间写入请求只能排队等待,这就是 T_lock。
增量同步原理
第二次搬家时小林学乖了:“能不能别总搬空仓库?”大刘点点头:“当然可以,增量同步就是只送新包裹。”他把一个快递员的角色引进来:每天凌晨,快递员只把当天新到的货和卖掉的货装上车,送到总部仓库。货少了,车轻了,时间从半小时缩到三分钟。增量同步的核心是增量窗口——一个“上次送过哪里”的记号,快递员只处理窗口之后的新数据,不再回望老数据。
实现增量同步的关键在于“判断哪些是新的”。最常见的手段是在源表里找一个变更标记,比如业务主键的自增序号、更新时间字段,或者事务日志。每次同步记录下当前取到的最大位置(业内叫水位),下次从水位之后继续取。这样同步的数据量从“全表 V”降为“变更部分 ΔV”,效率和实时性都大幅提升,可以按分钟甚至秒级调度。
快递员轻装上路,小林终于松了口气。但大刘提醒他:“快递员能干活,前提是每个包裹上都贴着发货时间。要是没有这个标签,他根本不知道哪些是新货。”于是,时间戳字段成了下一个要解决的问题。
- 变更数据量ΔV 表示两次同步之间发生变化的行数及对应体积,是全量 V 的一个极小子集。
- 传输速率不变R 仍然是网络传输速率,但传输对象从整表变为变更集合。
- 窗口推进同步完成后水位 t 更新为本次最大变更时间,保证下次不重复取数。
- 效率对比当 ΔV 远小于 V 时,增量耗时远小于全量耗时,调度频率也可随之提高。
时间戳字段
快递员拿到的新包裹都贴着一张面单,写着下单时间。增量同步也一样,源表里通常要有一个“面单字段”——updated_at(最后更新时间)或 created_at(创建时间)。大刘在小林的订单表里检查了一遍,发现每行订单都有updated_at字段,下单、改价、发货都会自动更新它。太好了,就用它当增量标记:同步时执行一条查询,只捞updated_at大于上次水位的数据,这就是增量水位推进。
但时间戳字段不是万能的。小林的分店开到了美国,那边服务器记录的updated_at是纽约时间,总部的水位却是北京时间,两边时差让快递员彻底懵了——不是漏送就是重复送。更棘手的陷阱是:如果订单被物理删除,这一行直接从表里消失了,updated_at永远不会再出现,增量同步根本感知不到删除动作。此外,如果业务代码偷懒没更新updated_at,数据变更也会悄悄溜过水位,造成静默丢失。
快递员渐渐发现,光看面单远远不够——要是店员忘记贴面单,或者包裹被小偷顺走,他永远察觉不到。大刘说:“别慌,咱们换一个更聪明的快递员,他不用看面单,只看记账本。”
- 过滤条件同步查询以水位移为下界,只筛选后续变更。
- 水位初始化首次同步时水位通常设为最小值或某历史时点,之后逐步推进。
- 水位更新每轮同步取本批最大时间戳作为新水位,保证不重不漏。
- 时区归一化多时区场景必须统一为 UTC 存储,否则水位比较失去意义。
CDC变更捕获
大刘给小林引入了一个“高级快递员”——CDC(Change Data Capture,变更数据捕获)。普通快递员要一件件翻货架找新货,高级快递员却直接站在仓库的安检门旁边,每件货进出时,安检系统都会自动“滴”一声,把货号记录到流水账本里。这流水账本是数据库自己写的,叫 binlog(MySQL)或 redo log(Oracle/PostgreSQL的 WAL)。CDC 工具(如 Canal、Debezium、Flink CDC)解析这些日志,就能拿到每一笔插入、更新、删除记录,实时转发给目标端。
CDC 的优势在于不侵入业务:它读取的是数据库底层的二进制日志,不要求业务表有updated_at字段,也不依赖业务代码配合。它本质上是把主从复制的原理拿来给 ETL 用——主库产生日志,从库/同步任务消费日志。每个日志都有一个位置编号(位点),类似于快递单号。同步组件记录当前消费到位点,下次从该位点继续读,保证变更不丢、不乱序。
有了高级快递员,数据几乎是“秒级”到达总部。大刘却按住了兴奋的小林:“高级快递员也会看走眼。比如数据库日志被误删、binlog 保留期太短,历史变更就查不到了。”所以,还得安排每月一次“盘点对账”。
- 日志位点每条变更在 binlog 中都有唯一偏移量 L,类似书签页码。
- 消费推进每处理一批变更,位点随之前进,增量恰好等于本批日志体积。
- 断点续传记住位点后,即使同步进程崩溃,重启也能从上次位置继续。
- 顺序保障同一条事务日志串行消费,保证业务上的先后关系不被打破。
全量比对方案
总部每个月月底都会派一位资深库管员到各分店“盘点”:对照电脑里的库存清单,一件一件数货架上的实物,发现对不上的就记下来修正。ETL 中的全量比对就是这个思路——定期把源表全量扫描一遍,和目标表逐行比对,把增量同步漏掉的、改错的、被删除的行找出来补齐。它是增量同步的“安全网”。
全量比对的工程实现,通常不会真的逐字比对两个大表,那样太慢。更聪明的做法是给每一行计算一个哈希签名(hash 行签名):把这一行的所有字段拼接成一个字符串,再用 MD5 或 CRC32 算出一个短指纹。比对时只需比较指纹:源端和目标端同一主键的签名一致,说明数据一致;不一致或目标缺失,就触发行级修正。由于全量比对要扫描全表,代价高昂,所以只能低频周期执行——比如每天一次或每周一次。
盘点那天,库管员果然揪出了三笔在增量同步中悄悄消失的退货单。小林感慨:“原来再聪明的高级快递员,也需要月末盘点兜底。”大刘笑道:“对,但要记得,快递员天天跑,盘点别太勤——不然仓库又要被搬空了。”
- 字段拼接将一行所有列值用分隔符连接成统一字符串。
- 哈希压缩对拼接串计算定长指纹,任意微小改动都会让签名面目全非。
- 分组比对按主键把源端与目标端签名放在一起比较,找出差异集合。
- 差异修正对差异行执行覆盖写入,目标端最终收敛到源端状态。
增量合并策略
快递送到总部后,不是往地上一扔就完事。库管员要拆开包裹、核对货号、查库存表——如果这个货号已经在货架上了,就把旧标签撕掉换上新的;如果货架上还没有,就找个空位摆上去。这个动作在数据库里有个学名:upsert(update + insert,更新或插入)。它由数据库的"INSERT …… ON CONFLICT DO UPDATE"这类语法实现,是增量合并的核心。
增量数据往往乱序、重复,比如同一笔订单被改了三次,快递员送了三个包裹。合并策略必须做到幂等——同一个包裹送十次,最终货架上的状态也只应该是最新一次的结果。用 upsert 处理时,主键(货号)冲突就更新,不冲突就插入,天然具备去重能力。对于需要保留历史的场景,比如流水表,则会改成“只在目标表追加新版本行”,用版本号区分,这就是历史保留策略。合并阶段的冲突处理要“温和”:以业务场景为准决定新值覆盖旧值,还是旧值保护新值。
小林看着货架上的标签焕然一新,满意地点点头。大刘拍拍他:“现在你手里有三样工具了——搬家的卡车、跑腿的快递员、还有月末的盘点员。问题来了:什么时候用哪个?”
- 尝试插入先把增量行按主键写入目标表,如果主键不冲突则直接成功。
- 冲突分支主键已存在时,执行更新替代插入,保留一行而不是报错。
- 新值覆盖
EXCLUDED表示本次尝试插入时被挡在外的行,用它覆盖旧值。 - 幂等保证重复执行同一合并,最终行状态一致,不会重复累积。
方案选型决策
小林有三个仓库,货量各不相同,大刘给他支了个招——选工具要看“货量、时效、预算”三件事。第一,数据量权衡:表只有几百行,直接全量,一分钟搞定;表有几个亿,天天全量就是灾难。第二,延迟要求匹配:老板要看实时大屏,必须上 CDC,让数据秒级流动;只要每日报表,时间戳增量就够。第三,成本资源评估:全量同步要占用大量带宽和数据库 I/O,增量同步要写解析逻辑、维护位点,CDC 还要多部署一套组件——每个选择都有隐性成本。
没有哪个方案是永远正确的“银弹”。工程上最常见的答案是混合策略兜底:首次用全量同步建立基线,日常用增量或 CDC 追平变化,每晚再用全量比对校验差异。小表直接全量,大表增量为主,核心交易表上 CDC,非核心报表用时间戳。选型评估可以量化为一个成本模型:总成本是数据总量、变更量、延迟要求的加权组合,权重由业务场景决定。
大刘给三个仓库分别开了“药方”:小仓库月结表走全量,中仓库订单表走时间戳增量,核心交易库上 CDC 加每日比对。小林照方抓药,数据链路终于不再半夜报警了。但大刘最后补了一刀:“方案定好了,链路要是没有监控,出了事你还在睡大觉。”
- 全量成本项αV 表示全量拷贝带来的固定开销,V 越大权重越高。
- 增量成本项βΔV 表示维护增量链路的花费,与变更量成正比。
- 延迟惩罚项γT_delay 表示同步延迟超预期时的代价,实时性要求越严,γ 越大。
- 决策原则求解最小化成本的方案,必要时组合多种手段。
同步链路设计
快递公司之所以能承诺“次日达”,是因为每一件包裹从揽收到签收,每个环节都有扫码记录。小林的数据链路也需要这样的“物流追踪系统”——链路监控告警。同步任务每跑完一轮,就上报同步行数、耗时、水位位置;如果某轮耗时爆炸、行数异常归零、水位停滞不进,监控系统立刻发短信告警。同步指标要统计数据质量校验结果:源端和目标端行数是否一致,主键是否重复,敏感字段是否为 NULL,这些都可以用校验 SQL 跑出来。
再好的链路也会出故障:数据库宕机、网络闪断、CDC 组件 OOM。设计时必须预留故障快速恢复路径:增量任务要记录水位,重启后从断点续跑;全量任务要支持断点重试,不能一失败就从头再来。把同步、校验、告警、恢复串成一个完整同步闭环,数据稳定性才有保障。衡量链路健康度的核心指标是 SLA(服务可用性),即一年中系统正常服务时间的占比——99.9% 意味着每年故障时间不超过 8.76 小时。
小林看着监控大屏上流动的同步曲线,第一次觉得数据像快递一样“看得见、追得着”。从搬家车到快递员,从盘点员到物流追踪,他终于明白:ETL 同步不是选一个工具那么简单,而是一套从采集、合并、校验到监控的完整系统工程。
- 可用时长正常运行时长等于总时长减去故障时长。
- 比率计算可用性百分比是正常运行时长占总时长的比例。
- 故障预算反过来算,给定 SLA 目标,允许的最长停机时间。
- 闭环保障监控发现异常 → 告警通知 → 快速恢复 → 比对校验,形成完整循环。
AI 应用场景
数据仓库 ODS 层初始化
阶段:数据接入与治理
解决的问题:企业新建数据仓库时,业务库的历史数据与每日新增数据需要统一入仓。传统手工导出导入无法保证一致性,且重复劳动严重;AI 时代的数据平台要求 ODS 层快速铺底并持续增量跟进。
具体案例:一家连锁零售企业搭建数据中台,数据工程师设计了“首次全量 + 每日增量”的调度策略:第一周用 Sqoop 全量抽取 20 张核心表到 ODS 层建立基线,之后每天按 updated_at 水位增量抽取当日变更,每晚再用全量比对任务校验一天的数据一致性。三个月后增量同步 0 漏数。
实时数仓 CDC 入湖
阶段:实时特征与流式处理
解决的问题:实时推荐和风控需要秒级看到用户行为变更,轮询同步延迟高且压垮源库。CDC 通过解析 binlog 实现近实时变更捕获,大幅降低对业务库的侵入。
具体案例:某电商平台的订单库接入 Canal 组件,实时监听 binlog 变更并投递到 Kafka,Flink 消费后写入数据湖 Iceberg 表。同步延迟从分钟级降到秒级,且无需业务表增加任何时间戳字段,订单取消等删除操作也能被准确感知。
电商订单增量合并
阶段:数据清洗与建模
解决的问题:订单状态频繁变更(待支付→已支付→已发货→已完成),同一订单多次更新会产生多条重复记录,直接追加会造成数据脏乱。使用增量合并策略可使目标表始终保持每条订单的最新状态。
具体案例:某跨境电商数仓团队用 Spark SQL 的 MERGE INTO 语法,把每日增量订单合并进订单明细宽表,按订单号去重,状态字段取最新时间戳的版本。配合删除标记位实现软删除,既保留完整历史又能快速查询当前状态。
Python 演示
class ETLManager: """ETL sync manager: full / incremental / compare strategies.""" def __init__(self, source, target, last_sync=0): self.source = source self.target = target self.last_sync = last_sync self.sync_count = 0 def full_sync(self): """Full sync: copy every row from source to target.""" for row in self.source: self.target[row['id']] = row.copy() self.sync_count += 1 return self.sync_count def inc_sync(self, ts_field='updated_at'): """Incremental sync: pull rows newer than watermark.""" new_max = self.last_sync for row in self.source: ts = row[ts_field] if ts > self.last_sync: self.target[row['id']] = row.copy() self.sync_count += 1 if ts > new_max: new_max = ts self.last_sync = new_max return self.sync_count def full_compare(self): """Full compare: scan source and fill missing / dirty rows.""" for row in self.source: row_id = row['id'] if row_id not in self.target or self.target[row_id] != row: self.target[row_id] = row.copy() self.sync_count += 1 return self.sync_count if __name__ == '__main__': src = [ {'id': 1, 'name': 'toothpaste', 'price': 15, 'updated_at': 100}, {'id': 2, 'name': 'towel', 'price': 25, 'updated_at': 120}, ] dst = {} etl = ETLManager(src, dst) print('full sync rows:', etl.full_sync()) src.append({'id': 3, 'name': 'cup', 'price': 30, 'updated_at': 200}) print('inc sync rows:', etl.inc_sync()) src[0]['price'] = 18 src[0]['updated_at'] = 300 print('inc update rows:', etl.inc_sync()) print('compare fix rows:', etl.full_compare()) print('target table size:', len(dst))
self.target[row['id']] = row.copy()按主键把源行浅拷贝写入目标字典,避免引用共享。if ts > self.last_sync:增量窗口的核心判断,只抽取水位之后的新数据。self.last_sync = new_max同步结束后推进水位,确保下轮不重复取数。if row_id not in self.target or self.target[row_id] != row:全量比对发现缺失或内容不一致的行。etl.inc_sync()第三次调用时源表首行价格已更新,增量窗口捕获到这次修改。
常见误区
误区既然增量又快又省资源,那所有表都应该用增量同步,全量同步是老古董,能不用就不用。
正解增量同步依赖可靠的变更标记,如果源表没有时间戳字段、没有主键、也没有开启日志,增量方案根本无从下手。而全量同步逻辑简单、天然完整,几百行的小配置表全量跑完只要几秒,比维护一套 CDC 组件划算得多。工具没有高下,只有适不适合——小表用全量是明智,大表用全量才是灾难。
为何常见:初学者容易从“性能最优”这个单一维度做判断,忽略了数据量、表结构和运维成本这些约束条件。
误区给表加了 `updated_at` 字段就能高枕无忧,所有新增、修改、删除都能被增量同步发现。
正解updated_at 只能感知更新和新增。物理删除会把整行去掉,时间戳无从更新;如果业务代码漏写这个字段,或数据库时钟回拨,还会造成漏数和错序。正确的做法要么用触发器/应用层保证时间戳可靠更新,要么用 CDC 读日志来覆盖删除场景,再配合全量比对兜底。
为何常见:初看时间戳字段很直观,“查到比我上次记录的时间还新的数据就是新数据”,但数据库底层删除机制和业务代码的不确定性很容易被忽略。
误区数据库不是本来就有 binlog 吗?那 CDC 是不是零成本,直接就能用?
正解binlog 是数据库的底层日志,它不会主动把变更推送给你。要把它变成同步能力,得部署 Canal、Debezium 或 Flink CDC 等组件,还要管理位点、处理 DDL 变更、解决日志过期问题,运维成本不低。CDC 的价值在于用组件复杂度换取业务零侵入和实时性,而不是白捡的便宜。
为何常见:把“底层存在日志”等同于“上层具备同步工具”,混淆了基础设施和业务能力的边界。
误区既然全量比对能发现不一致,那就每隔一小时跑一次,保证数据永远正确。
正解全量比对要扫描整张源表和目标表,计算每行哈希并比对签名,其资源消耗不亚于一次全量同步。对几亿行的大表频繁执行,会对数据库造成极大压力,反而拖垮业务。正确的姿势是低频兜底——每天或每周一次,配合增量同步的即时性,才是成本与可靠性的平衡点。
为何常见:只看到比对带来的“正确性收益”,忽略了扫描全表带来的“性能成本”,缺少工程上的权衡思维。
误区上线时选定了增量同步方案,就一直用下去,反正调度没报错。
正解业务是动态的:订单表从百万行涨到十亿行,原来好用的时间戳增量开始严重延迟;新的核心库有秒级实时需求,原先的每日批次完全跟不上;甚至源数据库从 MySQL 迁到了 PostgreSQL,原来的 binlog 方案也得换。选型决策需要定期复盘,当数据量、延迟要求、成本预算发生量级变化时,就要重新评估全量、增量、CDC、混合策略的取舍。
为何常见:把技术选型当成一次性决策,忽视了数据规模和业务需求是持续变化的变量。
面试题
Q1. 以下哪种场景最适合使用全量同步?
- A.亿级订单表的秒级实时同步
- B.小型维表的一次性初始化← 正确答案
- C.高频日志流的毫秒级同步
- D.超大主表的无锁持续增删改
答案:B。全量同步简单可靠,适合数据量小、变更不频繁的维表初始化。亿级订单表和毫秒级日志流对实时性和性能要求极高,属于增量或 CDC 的主场。超大主表全量会长时间锁表,因此选 B。
Q2. 增量同步能正常工作的先决条件是什么?
- A.目标表必须配备复合主键
- B.源表存在可判定的变更标记← 正确答案
- C.源表数据量必须超过百GB
- D.目标库必须支持分布式事务
答案:B。增量同步依赖时间戳、自增序号或日志等“变更标记”来区分新老数据,这是唯一硬性前提。目标表主键和分布式事务与增量能力无直接关系,数据量大小也不是必要条件。故选 B。
Q3. 以下哪项是时间戳增量同步的经典陷阱?
- A.修改操作会刷新修改时间列
- B.物理删除无法触达时间戳← 正确答案
- C.时间戳无索引也可高效过滤
- D.多源系统时区差异毫无影响
答案:B。物理删除会直接移除整行数据,updated_at 字段无从体现,增量同步自然感知不到删除。A 是正常设计而非陷阱;C 中无索引过滤必然慢;D 中时区不统一会直接导致水位混乱。故选 B。
Q4. CDC 变更数据捕获相比传统时间戳轮询的优势有哪些?
- A.实时性远高于定时轮询← 正确答案
- B.对源库性能压力更小← 正确答案
- C.无需数据库日志支持
- D.能感知删除操作日志← 正确答案
答案:ABD。CDC 直接解析 binlog,无需扫描业务表,因此实时性高且对源库压力小,同时日志中包含 DELETE 事件,能感知删除。C 恰恰相反——CDC 必须依赖数据库日志,没有日志寸步难行。
Q5. 全量比对方案在 ETL 链路中的主要用途是什么?
- A.实时写入高并发业务请求
- B.发现增量同步遗漏差异← 正确答案
- C.提升源库查询响应速度
- D.替代业务主键的生成
答案:B。全量比对通过扫描源端并对比目标端,找出增量同步漏掉、改错或删除的数据并补齐,是数据一致性的“安全网”。它不承担写入加速、查询优化或主键生成职责,因此选 B。
Q6. upsert 合并语义的正确理解是?
- A.存在则更新不存在则插入← 正确答案
- B.只允许插入不允许更新
- C.先全表清空再批量插入
- D.仅更新已有忽略新记录
答案:A。upsert 是 update + insert 的合体,核心语义就是主键冲突时更新、无冲突时插入。B 是纯插入,C 是全量重建,D 是只更新不插入,都与 upsert 语义不符。故选 A。
Q7. 设计一条健壮的增量同步链路,必须考虑哪些因素?
- A.变更顺序的一致性问题← 正确答案
- B.重复数据的幂等处理← 正确答案
- C.删除操作的传递同步← 正确答案
- D.源库物理磁盘总空间
答案:ABC。增量链路要保证同一主键的多次变更按序落地,重复投递时结果一致(幂等),同时要把删除操作正确传递到目标端。源库磁盘总空间与增量链路设计没有直接关系,属于无关干扰项。
Q8. 基于 binlog 解析的 CDC 同步,核心依赖是什么?
- A.依赖源库的查询优化器
- B.依赖数据库事务日志位置← 正确答案
- C.依赖目标库的存储过程
- D.依赖网络路由设备配置
答案:B。CDC 同步依赖 binlog 中的事务日志位点(offset)来记录消费进度、实现断点续传。查询优化器只影响 SQL 执行计划,目标库存储过程和网络路由设备与变更捕获无关,故选 B。
Q9. 数据仓库 ODS 层首次接入海量业务数据时,推荐哪种策略组合?
- A.全量初始化叠加增量追平← 正确答案
- B.长期只跑增量不补基线
- C.全量比对后放弃目标表
- D.依赖手工导出文件灌入
答案:A。海量数据首次入仓应先做一次全量同步建立基线,再用增量或 CDC 持续追平新增变更,兼顾完整性与效率。B 没有基线无法工作,C 放弃目标表等于没做,D 手工灌入不可扩展。故选 A。
Q10. 以下哪些属于合理的全量与增量混合调度策略?
- A.首轮全量建立数据基线← 正确答案
- B.定期全量比对校正偏差← 正确答案
- C.增量失败后自动降级重建← 正确答案
- D.全量期间永久禁止增量
答案:ABC。混合策略的核心是“全量建基线、增量追变化、比对做校验”,增量链路故障时临时切回全量重建是常见的降级手段。D 中“永久禁止增量”会让数据永远停留在全量时点,违背混合调度的初衷,故不选。