将 Excel 上传网站并导入数据库,如何进行设计?

2018-09-19 20:15:18 +08:00
 Kcelone

tornado + celery + redis + mysql。

1.由于当 Excel 文件过大时,上传及导入数据库时需花费较长时间,所以采用 celery 异步处理,首先将 Excel 保存作为临时文件上传保存服务端本地,然后进行 Excel 文件解析操作,并将数据导入数据库。

2.导入时牵扯到数据重复问题,此时采用临时表进行数据去重,当前实现的方式是原生 sql ( orm 有点 hold 不住),创建临时表, 临时表去重, 然后临时表及主表进行 join 筛选出新数据,然后进行插入。经过一番折腾,算是达到了预期目标,然后再继续下面的坑。

3.导入后,需将导入结果返回给界面,比如 Excel 中的数据是有问题的,由于 celery 异步方式,无法将结果返回给主程, 所以请教了下别人,说是可借助数据库新建一张表,负责记录导入结果。

  1. 那么,下面就是新建表的问题,如何建这个表呢? 个人觉得需要有个字段来记录导入的数据的唯一性,然后通过这个字段进行筛选查询当前导入的是哪些个数据。

我的思路就是这了,我想问一下有没有别的方式,好的方式,主要问题就是在这个异步线程结果获取这里,因为上传导入数据库是需要花费不定时时间的,无法上传后立刻判断 celery 的 task 的 id 和状态。

4145 次点击
所在节点    Python
34 条回复
Kcelone
2018-09-19 20:16:35 +08:00
总的来说,就是 Excel 上传导入数据库引发的一系列问题及思考。
Kcelone
2018-09-19 20:19:00 +08:00
我发现不经常和人沟通的一个重要的问题就是无法用语言描述自己的想法。
wayne1027
2018-09-19 20:36:58 +08:00
上传时记录操作人,操作时间,生成 ID ( table_A ),传完后对服务器上的 excel 进行 rename, xxx_uid_id.xlsx,这样一旦后端导入异常时可以读取 excel 文件名中的 id,根据 id 匹配 table_A 中的 uid,发送邮件或者短信通知任务状态。
Kcelone
2018-09-19 20:52:15 +08:00
@wayne1027 嗯,有点启发,我目前是 table_M 表示目的表( excel 中的数据存放表),table_L 表示日志表(记录 Excel 导入过程中,哪些数据异常,给用户以提示,文中说的那个新建表来记录导入数据的问题,说的就是这个 table_L ),当然除此之外还有一个临时表用以数据去重。我想得到的方式是,在界面上,就将导入的结果显示出来(也就是第一步上传导入数据库,第二步,从 table_L 中查当前所操作的表的产生的日志,并返回给界面。如果是用邮件或者短信息的话,可以,但没办法,应该不会被领导接纳。不过我想可以,模糊匹配 table_L 中的那个具有唯一性的关键字,然后根据时间排序取最新的,也就能保证是最新插入的数据了,这样应该就可以取出来操作日志了)。大神觉得如何?
Kcelone
2018-09-19 20:54:33 +08:00
@wayne1027 还有个问题就是,我并不能知道跑在 celery 中的这个读 Excel 并导入数据库的操作是否已经完成,如何判定这个状态呢?因为没有完成的话,我去查 table_L 中的数据的话,也是会出问题,这该怎么办才好,再支个招吧。
abusizhishen
2018-09-19 21:03:17 +08:00
转 csv 文件,load data infile ignore into 导入,轻松导入,相同记录跳过
Linxing
2018-09-19 21:07:21 +08:00
索引唯一性 加上楼上那位的做法
shuperjolly
2018-09-19 21:15:30 +08:00
个人觉得过大的 excel 先在前端校验或者客户端脚本或者程序校验好了再上传会是更好的选择
Moorj
2018-09-19 23:46:36 +08:00
先导入到临时表中校验,完成去重,填写不规范等问题,最后导入数据库
Eds1995
2018-09-20 08:33:13 +08:00
用 pandas 来处理 Excel 数据(标题校验等等),用 marshmallow 来校验数据,最后插入数据就看你用啥 orm 或者 sql。总的来说一次性导入 1 万条数据是可以接受的,只是内存会涨 100M 左右,超过 10 万数据导入直接就无法接受了,所以你还要限制上传文件大小。
Eds1995
2018-09-20 08:35:01 +08:00
celery 是可以更新任务状态的,你可以调用查询任务接口来获取任务状态,比如上传完成你更新状态 20%,数据处理完 50%,数据校验 70%
valkyrja
2018-09-20 08:37:29 +08:00
给 celery 配一个 backend,生成异步任务后会返回一个 task id,用这个 task id 去轮询就可以拿到任务的执行状态和执行结果
Kcelone
2018-09-20 09:54:45 +08:00
@abusizhishen 这个已经不是转格式的问题了,利用 Python 的一些库也可以将数据导入,数据重复也做了处理,现在的问题是,我把数据处理放到了 celery 中进行处理,这样主线程无法获取到 celery 的处理结果,因为数据导入后,某些处理结果日志还是要返回给前端的,现在无法获取到 celery 的处理状态,就不好进行下一步查询结果。
Kcelone
2018-09-20 10:00:51 +08:00
@Linxing 这么说吧,比如有个 100m 的数据大小的文件要导入数据库,那么使用 celery 的话,主线程可以立刻返回给前端结果,比如上传成功,导入成功,(而且 celery 处理完之后,会把一些处理日志放到了 table_L 表中),实际上,celery 还在处理过程中国,当 celery 的处理状态还是 PENDING, 我就无法获取到 table_L 表中的日志情况,因为我现在要把处理日志返回给前端,告诉用户,那些数据异常,需要处理,现在是这个问题了。还有就是索引唯一性,也是去重的一个方式,不过我采用的是临时表的方式。
Kcelone
2018-09-20 10:12:33 +08:00
@shuperjolly 应该不太好吧,应该是没有哪个系统是放到前端进行校验的,容易出问题,一般这种校验都是放到后端来做。
Kcelone
2018-09-20 10:13:16 +08:00
@Moorj 对,目前采用的方式就是这样,主要是这个 celery 啊,有坑在里面,具体的可以看下我其他的回复。
saulshao
2018-09-20 10:13:35 +08:00
我曾经提供过类似的方法,基本思路是与用户交互的程序负责接收其他真正的导入或者数据计算程序的状态或者消息。
错误提示显示给用户看,或者将这些错误消息(日志)持久化,等待用户回来查询。
Kcelone
2018-09-20 10:14:05 +08:00
@Eds1995 嗯,之前文件大小的事,没有考虑,现在确实有必要了。
sonyxperia
2018-09-20 10:15:41 +08:00
先导入到 tablea 保存所有 excel 文件的记录,再从 tablea 表处理数据到 tableb ?
Kcelone
2018-09-20 10:16:21 +08:00
@Eds1995 而且,我记得 Python 执行程序时,内存超过一定大小,就会报内存错误,记得当时上传镜像文件时,超过某个值(估计 200M 左右,没具体研究过)后就会报错,就是内存爆了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/490954

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX