读取处理 excel文件内容,循环处理的有什么优化方式吗?


//读取 excel 文件内容

//业务要求实时返回异常信息,老师好实时修订学生数据,不能走异步执行
$items->chunk(2000)->map(function ($sheets) use (&$errorData) {
    foreach ($sheets as $key => $sheet) {

            //目前每一列的验证会涉及查询数据库 (如学生账号/ 学校/ 学段  /年级/班级)都是独立的表 ,原来导入五六千学生挺快的几秒,现在主表学生 200 多万,每年学生增加100 万左右,
目前1000多条都需要十几秒


            //每一列excel文件给的都是中文 ,xx学校 / xx班级
            //大致会对每一列学校层级对应关系是否一致/存在 (学校->学段->年级->班级)查询 / 检验/这个是查询的数据库/索引走了




   }

   //最终包装完数据会涉及批量添加 / 更新 / 以及和http请求另外一个系统请求同步

   //批量添加日志信息每一个执行的详细日志,表里也几百万
});
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 18
随波逐流

可以考虑下 swoole 协程

4个月前 评论
随波逐流 (作者) 3个月前
zds 3个月前
随波逐流 (作者) 3个月前

你现在慢是因为 (目前每一列的验证会涉及查询数据库) io开销大, 数据量大了 ,查询变慢了 所以导致你导出时间边长了,

4个月前 评论
  1. 可以考虑使用xlswriter来优化读取文件的速度
  2. 其次可以考虑是否业务上可以限制每次只能上传一个学校的数据,这样可以减少很多的范围性的查询
  3. 在查询数据前可以对数据进行数据分组 ,比如按照你说的层级去分组,分组的过程中收集层级的名称的对应id关系(年级列表),然后每次foreach处理一个层级的数据
  4. 异常信息可以在数据分组的时候 先返回,没问题再执行更新等操作,日志可以考虑交给消息队列处理
4个月前 评论
令龙小道 (作者) 4个月前

1.合理设置数据库索引

2.检查查询是否命中索引

3.需要通过合理的方案减少数据库查询次数,如果每条都要查一次数据库,肯定会很慢的

举个简单的例子,导入的时候通过游标读取,累计到100条记录时候处理一次,查询数据库时把这100条数据所需要检验的数据一次性查出来,再通过遍历数据去检验,最后批次处理好数据后再批量添加数据

4个月前 评论
kkokk (作者) 4个月前

chunk函数的意义就是批量处理,所以你就按照批量处理的思维去处理数据库业务,目的就是减少数据库IO次数,例如每次读取100条,100条组装SQL去查询对应的表(按学校班级分组好数据,设置好索引),如果存在小表且业务字段简单的,可以使用链接查询,组装好数据批量写入,这样会提高不少。

4个月前 评论

chunk的话建议使用chunkById

还有就是 excel问题,用这个excel,省内存

file

4个月前 评论

根据这个量, 第一步应该还是异步,在发送异步队列的同时把本次异步记录(类似文件分片上传),然后在前端通过轮询,socket来请求异步是否完成,异常,然后做相应的操作; 第二是学校层级检验相关数据是否可以在循环前组装到本地(增大本地内存开销)

4个月前 评论
jiangjun

《原来导入五六千学生挺快的几秒,现在主表学生 200 多万,每年学生增加100 万左右,目前1000多条都需要十几秒》,从这里看,原因是就是数据量大了,数据库变慢了。 $items->chunk(2000) 这句话没有意义。下面都是每条循环了,为什么还要外面加一层循环? 1.首先看可以不可以,把每条验证,改为批量验证。几千次查询数据库,放在一个sql里面。 2.索引加的对不对 ,从你描述来看,索引加的还是有问题,200万的数据,不应该性能退化怎么快,建议每条sql研究一下 3.另外的方法再异步,fpm收到请求放入异步队列,前端使用轮询的方式查看处理进度,报错信息。这样用户和同步的感受是一样的。

3个月前 评论
sanders

即便是老师想实时修数据,是否可以考虑异步执行,通过 websocket 响应检测到的异常内容?

3个月前 评论

关于批量添加和excel导入这两个功能,和我几周前提问的问题差不多,既然要求实时,就不应该使用excel的方式去实现,而是使用批量添加。目前我在项目里采用的是方案一,如果感觉分批调接口会对服务器照成影响,可以考虑走websocket

3个月前 评论

我的建议是放到队列里面,多个消费者异步处理,excel也可以考虑流式读取, 至于实时修改?我只会说两个字"离谱"!

3个月前 评论

其实当你遇到这个问题时候,你也意识到这种设计在之前可能符合,随着业务的变化,程序之前所设计的方案其实都能重构。比如现在数据很大,里面有处理的逻辑什么的,可以将excel 转成普通的csv或者普通文件,采取逐行获取,写入中间表,再从中间表去实现你的最终完善逻辑,有些东西并不是一成不变,学会变通,技术架构都是一点点踩坑走出来的

3个月前 评论
Buffett-Cai

你这个场景需要优化的应该是单条信息的查询,导入一千条肯定要循环一千次,每次查询判断耗时1ms那就是需要至少1s才能完成判断,但是能优化到0.1ms就相当于性能提高10倍。excel提供的应该不是数据主键,循环查询的逻辑里应该在第一时间把数据主键查出来。查其他表的时候不要分开查,尽量使用主键连表拼在一起把你要的字段单独选出来,不要用其他字段去查表。如果架构允许动可以把学生信息提前缓存到redis,key=>value(学生唯一标识=>学生信息json)的形式把热数据(比如在校生)缓存起来,excel导入的时候就可以先在redis中查询,redis没有这个key再去数据库查。

3个月前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!