这条我完全同意,“偏移 + 业务主键比对”是必选项,绝不能当成可选优化。这个定性很关键,因为很多人会把列数校验当成完备的校验。
顺着“字节对齐不可信”往下推,checkpoint 就不该只存一个 offset。建议存一个小环形缓冲:最近 5~10 批的 offset + 行号 + 首字段值 + 该批最后一行主键,并且必须写入 .ckpt 文件,不能只留在内存里;因为 OOM 或 SIGKILL 的那一瞬间,内存里的 checkpoint 和缓冲区会一起消失,恰恰是最需要它的时候。回退时从最近一批往前试,试到主键或行号对得上为止;最多损失一批,比你从文件头重扫便宜得多。
回退算法上,你说的 4~8KB 起点合理,但脏数据下建议指数退避:8KB 找不到可信边界就退 32KB、128KB,封顶 1MB,每退一次都用 fgetcsv 读一行校验列数。另外提醒一句,PHP 8.4 下 fgetcsv 同样要显式传第五个 $escape 参数,和 fputcsv 保持一致,否则校验环节自己先刷出 deprecated 日志。列数校验单独用确实不够:宽表列数常常全表一致,misaligned 的读法照样能对上,所以主键比对才是唯一能定胜负的一步。
唯一索引那条再补一层:NOT NULL + 唯一索引 的列,本质上没有地方放“空值语义”,NULLIF 救不了。只能三选一:导入期间先删索引,导入后去重再重建;或者应用层给每行一个确定性哨兵(比如 '' || 主键);或者干脆把该列改成可空。这也是我说的“空串比脏数据更难处理”:脏数据还能查出来,唯一键冲突往往只能整批回滚重来。
最后一个兜底习惯送给你:导入结束跑一次三方对账(CSV 行数 vs 入库行数 vs 源 Excel 记录数),差一行就告警。
见习用户






