外键约束导致INSERT失败时应临时禁用再恢复;NOT IN易引发性能与逻辑错误,推荐LEFT JOIN+IS NULL;跨库同步应直连主库并控制批次大小;JSON字段外键需用函数提取而非字符串匹配。
外键约束导致大批量 INSERT 失败:先禁用再恢复
同步过程中遇到 error 1452 (hy000): cannot add or update a child row,本质是目标库外键检查拦住了非法关联数据。别硬扛——临时关闭比逐条校验快十倍。
- 执行前确认目标表无正在运行的事务,否则
SET FOREIGN_KEY_CHECKS = 0可能被回滚覆盖 - 仅对当前会话生效,
INSERT完毕必须立刻执行SET FOREIGN_KEY_CHECKS = 1,漏掉会导致后续数据静默损坏 - MySQL 8.0+ 在并行 DML 场景下,即使关了外键检查,
INSERT ... ON DUPLICATE KEY UPDATE仍可能因唯一索引触发锁等待,需配合innodb_lock_wait_timeout调整
百万级 JOIN 同步慢得像卡住:用 LEFT JOIN + IS NULL 替代 NOT IN
做增量比对时写 WHERE id NOT IN (SELECT id FROM target),数据一过五十万就变“假死”。根本原因是子查询无法走索引,且 MySQL 对 NOT IN 的空值处理极不友好。
-
NOT IN遇到任意NULL值,整个条件直接返回空结果集,逻辑错得无声无息 - 改用
LEFT JOIN target ON source.id = target.id WHERE target.id IS NULL,确保两边id字段都有索引,性能提升通常在 5–20 倍 - PostgreSQL 用户注意:
NOT IN行为一致,但可直接用EXCEPT,语义更清晰、优化器也更愿意下推过滤
跨库同步主从延迟高:跳过从库复制,直连主库拉取
很多团队默认让同步程序连从库读取 binlog 或查数据,结果发现延迟十几分钟起步。不是网络问题,是复制链路本身就在排队。
- 除非业务明确要求“最终一致性”,否则同步任务应直连主库——
SELECT和INSERT都走主库,避免复制延迟干扰判断 - 主库压力确实上升?那就控制并发数:
INSERT ... VALUES (...), (...), (...)批次大小设为 1000–5000 行,比单行插入快 10 倍以上,又不至于撑爆主库内存 - 若必须走从库(如主库禁止长查询),至少加
SELECT ... FOR UPDATE强制读已提交,否则可能读到半截更新的脏中间态
JSON 字段里藏外键 ID:字符串匹配不可靠,提前解析再关联
有些老系统把关联 ID 存在 meta 字段里,比如 {"user_id": "12345", "order_id": "67890"}。直接用 LIKE '%\"user_id\": \"12345\"%' 查,不出三天就查出错数据。
- JSON 字符串格式稍有变化(空格、换行、引号转义)就会漏匹配;更糟的是,
user_id出现在别的字段值里也会误中 - MySQL 5.7+ 用
JSON_EXTRACT(meta, '$.user_id')提取后再转成数字比较;PostgreSQL 用meta->>'user_id',都支持走函数索引 - 如果 JSON 结构深度不定或含数组,别手写正则——用
JSON_CONTAINS或@>操作符,它们专为嵌套校验设计,稳定得多
外键冲突从来不是数据问题,是同步节奏和校验粒度没对齐。最常被忽略的,是把“一次全量校验”当成“持续状态对齐”——只要源和目标之间存在任何异步环节,就必须按时间戳或版本号切片校验,而不是依赖某次快照。










