Files
sentinel-home-ai/.workbuddy/memory/2026-08-29.md
ericwyuan 988c63a8f9 fix(fam-core): 修复 sync_identity_map 增量同步 1062 主键冲突导致游标卡死
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>
2026-08-29 23:11:10 +08:00

38 lines
2.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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'")`,游标永不推进
### 根因(两层)
1. **镜像表主键设计缺陷(主因)**`sync_identity_map` 以 Oracle `person_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 分钟重复失败。
2. **陈旧 __pycache__部署陷阱**NAS 上 `.pyc` 时间戳比 `.py` 新(部署时 `.py` 带旧 mtime 拷贝),
Python 信任 pyc 加载了旧逻辑;另曾有两个 gunicorn master 并存8487/10914只有一个绑 8000。
### 修复
- **db_layer.py `upsert_sync_identity_map` v2**:镜像表改为 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/trigger` ok拉 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 被加载(已踩坑)