关于大表数据导出方案设想

本方案和需求都是本人设想仅代表个人观点,没有实际开发过,肯定有很多细节需要推敲,这里针对粗劣的需求提供解决方案。实际使用还请看实际需求和相关资源情况。

背景

   很多时候我们需要系统做表格导出的功能,excel或csv,或记事本等等功能需求。本质上这种情况是我们产品功能不完善或不被信任或没有挖掘用户真正需求或很难针对性个性开发的表现。

   这样就出现了数据导出的需求,但是对于一个很大的表有着几百万上千万数据的表中如何将数据有格式的导出到文件中那?

 

   其中这有几个比较棘手的问题:

  1.  数据量大,查询条件多
  2. 要求导出数据多一般几万条或是十几万条数据
  3. 一般常规导出方式耗内存和长时间占用数据库资源导致业务操作缓慢           

   当然这种数据导出业务上也有几个特点:

  1. 即时性要求低,肯定都是导出前一段时间的数据,用来做必要的特殊分析
  2. 第一点提到的一般这种数据都是以时间为最基本的切分维度

   根据上面的几点情况分析我们需要实现的导出功能要对业务要求的即时性和技术处理可实现度达成一个有效的平衡。

方案

    针对上面的需求我们要实现一个折中的方案,也就是说我们既要满足用户需求,同时也要尽量小的造成系统(包括数据库)压力。

    折中方案一般是客户提前预约导出数据请求,系统异步后台导出。

    具体方案先看如下图示:

 

具体方案说明:

1. 首先创建两张表,一张是导出数据表(这个表一般是订单表等业务主表),另一张是新建的任务表
  • 导出数据表就是存在各种字段,数据量比较庞大
  • 任务表就是用户的预约期望表,其中包含需要的数据的查询条件,起始和结束时间是必须的,然后还有一些就是针对用户自己的筛选条件,期望获取时间等(任务表不一定需要在前台展示给用户,或者明确的要求用户填写,我们可以在主表查询界面的“导出”按钮作为插入任务表的数据)
2. 数据导出服务设计
  • 由于我们的需求一般都是有规律的,比如一天一次,一个月一次,一周一次等,这样我们就需要针对任务表的设置来定时处理(quartz是个不错的选择)
  • 我们是针对任务来读取相关数据,导出文件形式的数据。如果针对一个用户开启一个线程来处理导出数据就基本够用了
  • 如果在一张表中有多个用户,他们需要的数据都是不同要求的,这时我们具体实现的难点
    • 我们可以将一周或一个月的数据分批读取出来,怎么分批那?
    • 通过开始和结束时间获取自增ID的最大和最小值
    • 有了最大和最小值我们按实际情况进行ID分批读取(这里我们读取的是全量数据哦!!)。
    • 将数据读取到处理程序,进行分类筛选,而不是在数据库中进行筛选。
    • 将筛选的数据根据用户任务表进行分类写入下载文件
    • 分批次循环(看实际情况设置循环是否需要间歇给数据库减轻压力),对下载文件进行增量写
    • 任务表中不断更新写入行数作为进度查看
    • 当数据导出完成的时候在任务表中列出下载文件的链接提供下载
  • 这样的话我们就避免一次查询数量过大导致内存不够用的情况,同时减轻数据库瞬时压力。
  • 通过自增ID(主键索引)的方式获取一个数字之间的数据对于mysql来说非常快,因为mysql数据和主键索引是存储在一起的(InnoDB)这样我们取数据比较快
3. 方案实现难点及特点
  • 方案实现关键在于读取数据本地内存筛选状态回写一系列操作的连续性与扩展性实现
  • 分段读取数据读取速度比较快
  • 我们可以将程序抽象成读取数据、数据筛选、数据转化、增量写文件,状态回写等几个大块进行业务解耦。
  • 数据读取和数据筛选可以单线程同步进行
  • 数据转化和增量写文件可以丢到另外的线程执行
  • 对文件增量写数据操作要注意细节
4. 方案缺点
  • 即时性不是很好(为了折中业务与技术)
  • 在大批量读取数据的时候如果中间读取出现问题,要有对应的方案解决
    • 假如我要读取10000条数据第5批次(每批次1000)失败了并且已经写入了500另外500条失败没有写入文件
    • 这个时候我们需要记录状态值来解决这个问题,从记录的状态值开始继续读取与写入
    • 如果状态值没有写成功或者写文件数据与写状态值没有完成一个原子操作就不可避免的造成一致性的问题
    • 造成上面一致性的问题,我们就需要在导出文件中读取最后一条写入的数据获取对应的比较信息或重复写入交给客户筛选处理(交给客户处理影响客户体验

本方案和需求都是本人设想仅代表个人观点,没有实际开发过,肯定有很多细节需要推敲,这里针对粗劣的需求提供解决方案。实际使用还请看实际需求和相关资源情况。

 
posted @ 2018-12-13 16:11  zygfengyuwuzu  阅读(718)  评论(0编辑  收藏  举报