ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

网格信息批量导入导出怎么做?一次三万条台账的工程复盘

2026/10/2 12:11:37 拓冰建站 浏览量
网格信息批量导入导出怎么做?一次三万条台账的工程复盘 一、三万条台账全量导入要四十分钟去年冬天接手一个镇的网格化管理模块甲方给了一张人员台账三万一千多条记录字段三十一个从姓名、身份证号、联系方式到网格编号、房号、是否低保谁家归到哪个格都写在表里。需求听着简单每季度更新一次要能一键导进来导错了得说清哪一行错在哪一步。第一版做得很朴素前端选文件后端逐行读、逐行校验、逐行写库。第一轮压测跑完三万条用了四十分钟中途因为一条重复记录整批回滚。更麻烦的是浏览器等到超时先断开用户看到的是失败库里其实已经落了一万多条第二次再导就变成重复数据只能人工比对这件事我们赔进去整整两天。二、直觉做法错在把三件事揉成一件把导入拆开看它至少是三件事。先把文本变成结构化记录再判定这条记录合不合格然后才是落库。第一版把三步揉在一个循环里任何一步慢整条链路就慢任何一步错整批就废错误处理也就无从下手。慢的根子在两处。一处是把整个文件读成一个巨大的列表放在内存里三万行乘三十一个字段再叠上解析出来的对象内存峰值冲到七百多兆村一级服务器只有两核四G跑到一半系统开始换页。另一处是逐行写库每条记录一次网络往返再加一次事务提交三万次往返本身就是分钟级的开销。错的根子在于校验发生在写库之后。数据已经进库了才发现某行的身份证校验位对不上此时要么整批回滚要么留下脏数据两条路都难看。合理的顺序是先判定再写而且判定结果要能和回执对上号用户看到行号才知道回表格改哪一格。三、三条路各自要付什么代价第一条路是用 ORM 的批量保存攒够一千条提交一次。代码量最少代价是对象本身占内存而且生成的语句仍是一行一条只是把往返合并了解析和转义的开销照样在实测三万条仍要八到十分钟内存峰值也没降下来。第二条路是走数据库自带的文件装载能力把文件整理成纯文本后一次性灌进去。这条路快十万行十几秒就能完代价很硬校验几乎做不了出错只能拿到一句笼统的失败提示而且要求数据库进程能读到那个文件跨机器部署时还得先把文件搬过去路径和权限都是麻烦。第三条是我们最后选的看起来最笨把校验挪到写库之前用分批加参数化批量插入。每批固定五百条批与批之间提交一批失败只影响这一批前面成功的保留回执把行号和原因一起给出去。用户改完表格重跑一遍靠业务键去重已经进去的不会再进第二次。四、把导入拆成四段定下来的结构是四段。第一段读文件只做一件事把每一行原样读成字符串数组不猜类型。第二段校验按列定义逐格判定必填、长度、格式身份证单独算校验位任何一格不过就把这一行整行挑出来。第三段分批写库开一个异步任务边写边把进度记在任务记录里。第四段出回执成功的条数、失败的条数、每个失败行号和原因一起生成一份文件让用户下载。四段结构在万村乐数字乡村的网格模块上前后改了三轮第一轮只有批量写第二轮补上校验第三轮才把异步和回执拆开。真正让它稳定下来的不是某个技术而是每一段只对上一段的输出负责中间不共享可变状态出了问题往前一段找就行。导出的链路同样要重新设计思路正好反过来。查库不能把结果集一次读进内存我们改成游标分页每页两千条取一批写一批到本地文件写完立刻释放引用。文件写满一个阈值就切一个新分片最后再按需打包整个过程内存占用是一条平的直线跟数据量大小基本无关。五、几个不能随手定的字段与参数列定义必须显式不能让表格解析器自己猜。手机号、身份证号、行政区划码、门牌号这些看着像数字的列一律按文本读否则十八位身份证会被转成科学计数法末几位直接变零门牌号的前导零也会掉。日期同理按文本读进来再自己解析避开被自动识别成本地格式。校验规则我们写成声明式绑在列上而不是散在各个判断分支里。加一列只改配置不改流程这一条在项目后期救过我们因为甲方半年内加了七八个字段每次都要动代码是不可能的。批大小也不是随手定的。小了提交次数多写库开销成倍涨大了单次事务太长锁持有时间久中断之后要重来的量也大。我们在五百到两千之间试了几轮最后按记录宽度定字段多的用五百字段少的用两千这一条后来写成了默认参数。六、上线后撞出来的三个坑第一个坑是身份证精度。表格里那列看着是数字第三方读表组件默认也按数字解析十八位整数超过了双精度的安全范围末几位直接变成零导进去以后校验位当然对不上回执里一片红。改法是打开文件的瞬间就把所有列声明成文本宁可多写一行配置也不让解析器替我们做类型推断。第二个坑是导出超时。镇里导出全量台账要四十多秒网关的等待上限是三十秒请求直接被掐断用户点一次失败一次。改法是把导出改成异步任务接口只返回任务号前端轮询进度文件生成好再给一个下载入口。顺手加了文件过期清理超过一天的临时文件自动删掉磁盘不至于被堆满。第三个坑是重复导入的幂等。村与村之间会有人员调入调出同一张表常常要连着导两次如果没有去重数据会翻倍。改法是给人员表加上身份证加网格编号的业务键写入时按这个键判断是新增还是更新重导同一份数据不会产生新行导错之后重导一次就能覆盖回正确状态。七、这层解决不了什么这套链路解决的是格式与入库管不了数据本身对不对。表格里写着一个不存在的网格编号校验位算得再准也没用这类跨表的语义检查我们放到导入之后单跑一遍列出可疑行让人工确认而不是硬拦着不让导。它也不负责合并同一人在不同村重复登记的情况。现实里一个人可能在娘家村和婆家村各有一份台账两边身份证一样、网格不一样程序只能按业务键判重判断不了哪个才是当前有效的那份这属于业务规则得由镇里给出口径。八、小结回头看整个改动里没有特别新鲜的算法值钱的是把一件被当成一步的事拆成了四步并且让每一步都能单独失败、单独重跑。三万条的导入从四十分钟压到八十秒左右失败回执能精确到行号重导不会造重复这三条加起来才让村干部真的敢自己动手导。从身份证末位变零到网关三十秒断连万村乐数字乡村网格模块上的每一条坑都对应一次线上返工。如果你们也在做批量导入导出建议先把列定义和业务键这两件事定死剩下的坑大半都能提前躲开。