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


//读取 excel 文件内容

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

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


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




   }

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

   //批量添加日志信息每一个执行的详细日志,表里也几百万
});
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 18
随波逐流

可以考虑下 swoole 协程

1年前 评论
随波逐流 (作者) 1年前
zds 1年前
随波逐流 (作者) 1年前

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

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

1. 合理设置数据库索引

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

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

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

1年前 评论
kkokk (作者) 1年前

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

1年前 评论

chunk 的话建议使用 chunkById

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

file

1年前 评论

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

1年前 评论
jiangjun

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

1年前 评论
sanders

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

1年前 评论

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

1年前 评论

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

1年前 评论

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

1年前 评论
Buffett-Cai

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

1年前 评论