Oracle→NAS 增量同步反复报 (1062, "Duplicate entry '1073-汤圆' for key 'uq_video_raw_uid'"),整批失败、游标永不推进,同步状态页卡在"同步中"。 根因:sync_identity_map 以 Oracle person_identity_map.id(代理自增键) 作 NAS 主键,但 Oracle 库重建/恢复后这个 id 会被复用——实测 Oracle 现在 的 id=744 对应 (1073,'汤圆'),NAS 上 id=744 还是旧的 (1302,'人物E')。 upsert 先按 PK id 命中旧行,UPDATE 成 (1073,'汤圆') 后与已存在的同名行 在 uq_video_raw_uid 上二次冲突。 修复:镜像表改为 NAS 本地自增 id 主键,业务键 (video_id, raw_uid) 唯一, Oracle 的 id 只落 oracle_id 列做溯源;upsert 的 UPDATE 子句不再改写 video_id/raw_uid 这两个键列,只更新 oracle_id/canonical_name/source 等。 ddl.sql 同步更新表定义。 已在 NAS 上完成现网迁移(ADD COLUMN oracle_id -> 回填 -> 主键改自增)并 验证:补拉同步成功恢复,游标正常推进,手动触发同步验证通过。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2.7 KiB
2.7 KiB
2026-08-29 工作日志
修复 Oracle→NAS 增量同步 1062 (uq_video_raw_uid 重复键) — 已部署验证
现象
- 同步状态页:状态"同步中"、
最近 —、本次增量 —、游标卡在2026-08-29 04:57:15 - 报错:
(1062, "Duplicate entry '1073-汤圆' for key 'uq_video_raw_uid'"),游标永不推进
根因(两层)
- 镜像表主键设计缺陷(主因):
sync_identity_map以 Oracleperson_identity_map.id作主键。 Oracle 端 id 是 AUTOINCREMENT 代理键,但 Oracle 库重建/恢复后 id 会被复用——实测 Oracle 现在的 id=744 是(1073,'汤圆'),而 NAS 上 id=744 还是旧的(1302,'人物E')。旧 upsert 的ON DUPLICATE KEY UPDATE先按 PK id 命中旧行,再把它 UPDATE 成(1073,'汤圆'),与 已有的(1073,'汤圆')行在uq_video_raw_uid上二次冲突 → 1062 → 整批失败 → 游标不推进 → 每 30 分钟重复失败。 - 陈旧 pycache(部署陷阱):NAS 上
.pyc时间戳比.py新(部署时.py带旧 mtime 拷贝), Python 信任 pyc 加载了旧逻辑;另曾有两个 gunicorn master 并存(8487/10914),只有一个绑 8000。
修复
- db_layer.py
upsert_sync_identity_mapv2:镜像表改为 NAS 本地自增id主键, 业务键(video_id, raw_uid)唯一;Oracle id 只落oracle_id列溯源;UPDATE 子句不再改写 video_id/raw_uid(只更新 oracle_id/canonical_name/source/updated_at/synced_at)。 - scripts/ddl.sql:同步更新表定义(
id INT AUTO_INCREMENT PRIMARY KEY+oracle_id INT)。 - 现网迁移:
ADD COLUMN oracle_id→ 回填oracle_id=id→MODIFY id AUTO_INCREMENT(无重复对, 迁移安全);修复早前测试误改的 3061 行 canonical_name。 - 部署:db_layer.py 用 stdin 管道覆盖 NAS;清空全部 pycache;杀掉双 gunicorn,单实例重启。
验证(通过)
- 09:55 一次补拉成功:
videos+260 events+1456 people+37 model_calls+744 identity_map+285,游标推进到 09:55:06 /api/status:last_error=null、last_sync_at有值;手动/api/sync/triggerok(拉 2videos/2events/1people/6calls/1identity)(1073,'汤圆')行已自愈:oracle_id=744;NAS 旧(744→1302,'人物E')保留不冲突
待办/注意
- 本地 repo 有未提交改动:
fam-core/src/fam_core/db_layer.py、scripts/ddl.sql(等用户拍板提交) - 同类隐患:sync_videos/sync_events/sync_model_calls 同样以 Oracle id 为主键,但 Oracle 侧这些表 只插入不 UPDATE、id 稳定,风险低;若将来 Oracle 也重建,需同样改法
- NAS 部署后必须清 pycache(或 touch .py),否则旧 pyc 被加载(已踩坑)