数据导出到excel优化

1,156 阅读2分钟

背景

日常开发中我们经常会遇到数据导出到excel的需求,由于导出的数据量大往往会出现内存溢出或者超时等问题。往往的做法也是从业务上去规避的,比如:

  • 限制每次导出的最大数据条数,比如控制在1000条
  • 通过时间搜索等筛选减少每次导出的数据量,分批次导出
  • 分页导出,每次只导出当前页,每页显示多一点数据

但是这样往往不能满足运营人员的需求,虽然做了优化,后续还是会偶尔出现超时等问题。这种时候优化的思路往往是同步导出优化为异步导出

异步导出

流程图

思路其实很简单,主要步骤如图:

  • 保存导出时的搜索查询条件,以及要导出的字段到mysql,同时写入redis队列里
  • 然后开启后台进程或线程去执行导出操作
  • 将导出的本地excel文件上传到云服务,然后回写excel文件地址到mysql
  • 页面增加导出记录项,提供导出文件下载的入口展示

数据库设计

 CREATE TABLE `export` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键自增',
  `source` varchar(20) NOT NULL DEFAULT '' COMMENT '来源,业务区分',
  `shop_id` int(10) NOT NULL DEFAULT '0' COMMENT '门店ID',
  `progress` tinyint(1) NOT NULL DEFAULT '-1' COMMENT '导出进度:-1:未执行, 0:正在执行, 1:完全成功, 2:部分失败',
  `condition` text COMMENT '搜索条件json',
  `download_url` varchar(255) NOT NULL DEFAULT '' COMMENT '下载文件地址',
  `export_result` varchar(255) NOT NULL DEFAULT '' COMMENT '导出结果',
  `operator` varchar(20) NOT NULL COMMENT '操作人',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_shop_id_source` (`shop_id`,`source`)
) ENGINE=InnoDB CHARSET=utf8mb4 COMMENT='文件导出下载表';

代码实现

代码可自行实现,可以起多线程,php的话如果用到swoole可以起多个协程处理。代码逻辑就是写入mysql后,同步写入redis一份,然后脚本跑的时候每次lpop出来一个进行处理,导出的excel文件上传到云服务(oss、七牛等)

页面展示

用MQ异步执行

以上除了mysql + redis,然后定时脚本执行的方式外,当然了用MQ也是比较好的选择,直接将导出任务发送消息到MQ,由mq里做整个的异步导出处理