记录一下处理经过。
最近遇到一个问题,我们有个车证系统,最近用户发现导出数据时页面上提示超时,无法获取到 Excel。
我通过查证之后发现,这个导出接口默认是导出系统内所有的车证数据,目前系统内有效的车证数量大概有 6~7K,按理说数据量不算大,查询数据然后再通过模板引擎生成 Excel 进行导出,怎么会耗时这么长,居然超过前端设置的30秒超时时间。
查看了代码逻辑后,发现里面的查询逻辑有点。。。。
我们有批次表、申请表、还有组织信息的表,通过获取系统中所有批次,再用获取到的批次号通过 in 进行查询,而且还有状态,一个查询里面有两个 in,难怪效率有点低,而且好像是没有索引的,应该是走的全表扫描。
关键是查询完之后,比如获取到 6 千条数据,还有循环 6 千次去查询组织表获取组织名称,因为导出的模板需要这个信息。。。。。 相当于又查询了 6 千遍数据库,我去,神逻辑。。。。。
我看了下申请表的结构,里面明明有组织ID、组织名称的字段,为啥不在申请的时候就写入这两个字段,搞得在导出的时候还要跨表查询,这怎么可能快嘛,而且随着使用得越来越久,导出的数据肯定越来越多,导出的时间就会越来越久。。。
而且,最近他们又有新需求,导出的时候还要加上审批的时间,又得关联审批表,想想这又是一堆查询,肯定更慢呀。
我在本地环境试了下,导出 6 千条数据居然要 2~3 分钟,这估计跟我的数据库配置和电脑配置也有关系,不过这个逻辑肯定要优化了。
关于优化的点:
- 在提交申请的时候强制写入组织ID、组织名称,这样后续查询到数据就不需要再单独进行查询了;
- 优化查询,根据批次号好像并没有必要,因为是查询所有批次,可以把这个查询条件去掉;
- 申请表中新增审批时间的字段,修改代码逻辑,审批的时候顺便修改这个时间;
- 针对老数据,加一个临时定时任务,把审批表与申请表关联起来,然后将审批时间写入到申请表中,这样新老数据就都要审批时间了,也不再需要跨表查询几千次了。
说做就做,我自己的开发环境改了之后发现效果很显著,现在导出时间可以控制在30秒左右(由于我的服务器配置太低,只能这么慢了 -.-),然后就是上线了,上线需要挑一个没人用的时间,因为需要跑定时任务刷数据。大概10分钟这样就跑完来了。然后再登录系统看看,导出时间不到 1秒!成果显著。
保守起见,当时还让前端同事把超时时间改为 60 秒了,现在看来好像没必要~
由此得知,MySQL 查询时 in 的效率是真的低,同时在查询大量数据时再进行跨表查询效率也非常低,即使每次仅耗时 1 毫秒,耐不住数据多啊,查询这么多次还浪费资源,在实际应用中尽量避免这个问题。
个人能想到的大概就这些,后续有想法再更新。。。。
TODO -----改天记录一下模板引擎 FreeMarker 的使用。
周五了,又可以愉快的过周末咯~
End.
Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/about-excelexport-timeout-fixed