活动预告

批量导出csv文件的基本尝试

杨建荣 2016-03-20 22:35:00
开发同学前几天给我提了一个数据查询的需求,大体是查询某个表的数据,然后把查询结果以csv的形式提供给他们,一般来说这种定制查询,开发的同学都会提供好语句,DBA同学只需要简单执行即可。
   每次看到语句,我都要简单评估一下,今天的语句看起来非常简单,需要在一个历史库中进行数据查取,从开发同学提供的语句来看,这个查询看起来真不简单。提供的数据都是近5年内的历史数据,所以我简单看了下,这个表有10亿的记录,而符合条件的数据就有1亿多条。从数据量来看,这个我是真没法提供了,数据结果集就肯定几十上百G了,发给开发同学肯定不现实的,而且就算这个坎能迈过去,他们也没法用啊,一个几十G的文件,本地几十M的文件excel打开都成问题,何况这么大的数据量。
   所以找到开发同学,想了解一下他们要拿这么多数据干嘛,需求的情况是怎么样的,简单聊了下,发现原来是数据仓库组的同事需要做大数据分析,发现以前的部分数据存在问题,所以希望DBA能够提供一些帮助,把存在问题的历史数据提供给他们,重新更新一下,所以按照这种情况,这个需求看起来似乎也是合理的了。大数据所需,DBA提供基础数据。
    所以一个很明显的问题摆在我面前,那就是如何高效的导出这部分数据,目前在这种异构的环境中,csv也是一个合理的一种方式,不过大数据部分的同事有个要求就是,因为大数据分析的需要,其实还是希望把这部分数据能够切分成多个文件,如果能够切分到天就最好了,他们就会有针对性的做一些处理。
   对我来说,还需要简单确认,以前把数据分片,切分以前也写过一个简单的工具,不过是在oracle之间的做导出比较给力,在这个场景里面需要马上满足他们的需求还是有些难度。
所以我简单分析了一下这个历史表的情况,可以拍着胸脯给他们肯定的答复了,按天是可以支持的,因为这个分区表就是按照日期进行分区的,每天都会有一个单独的分区。
有了这些信息,我就风风火火开始了数据导出。
   当前的环境有100多G的空余空间,感觉应该是够了,所以就写了下面两个脚本。ora_exp.sh,ora_csv.sh
ora_exp.sh会调用ora_csv.sh ,ora_csv.sh的作用就是把数据通过sqlplus的spool方式把数据以分区的粒度进行导出。

date=`date -d "+0 day $1" +%Y%m%d`
enddate=`date -d "+1 day $2" +%Y%m%d`

echo "------------------------------"
echo "date=$date"
echo "enddate=$enddate"
echo "------------------------------"

while [[ $date < $enddate  ]]
do
  echo $date
  sh ora_csv.sh $date  > test_server_log_$date  &
  date=`date -d "+1 day $date" +%Y%m%d`
done

ora_csv.sh的脚本内容如下:
sqlplus  -s / as sysdba <
set pages 0
set feedback off
set echo off
set trimout on  
set trimspool on
set linesize 500
set headsep off
select
 ID             ||','|| 
 SN             ||','|| 
 GROUP_ID       ||','|| 
 SERVER_IP      ||','|| 
 SERVER_NAME    ||','|| 
 ....
 CLIENT_STYLE    csv_col
from test.test_server_log partition (SERVER_LOG_$1) ;
EOF
这个脚本一旦运行,就会同时开启多个导出的session,每个分区都会有一个独立的session来导出相应的数据,分区的命名也是规范的,这就为导出提供了很大的便利。
比如导出2011年8月2日到2012年10月1日的数据,就可以这样运行脚本
sh ora_exp.sh 2011-08-29  2012-10-01
但是第一次导出的时候,为了省事,给了一个较大的时间范围,结果同时上百个session导出,风风火火,速度确实还是很快,但是马上碰到的问题就是空间开始告紧。
尽管自己也删除了部分的数据,但是最后还是有一部分的导出失败,总体的感觉就是这种方式看起来还是比较快,但是不太可控,尤其某一个小的环境出问题还是不太好定位。
所以吸取了经验,调整了时间范围,把它切分为多个时间段,导出的文件马上压缩,按照测试的数据来看3G的文件压缩后大概在500M,压缩比还是比较理想的,按照这种情况就需要简单评估最多需要开启多少个并行的导出session了。
以一个dump最大3G的标准,压缩比为500G,有100G的剩余空间,那就是100/3.5总体能够开启30个并行的session了。
所以按照这个基本的思路,就在ora_exp.sh脚本中加入了压缩的部分。每个时间段都是串行执行。
date=`date -d "+0 day $1" +%Y%m%d`
enddate=`date -d "+1 day $2" +%Y%m%d`

echo "------------------------------"
echo "date=$date"
echo "enddate=$enddate"
echo "------------------------------"

while [[ $date < $enddate  ]]
do
  echo $date
  sh ora_csv.sh $date  >test_server_log_$date 
  gzip test_server_log_$date 
  date=`date -d "+1 day $date" +%Y%m%d`

done
按照这个思路导出之后。在个把小时过后,终于告一段落,一看压缩后的文件有近69G,按照压缩比,源数据应该有400多G,这种方式还是比较理性的。
[oracle@statg data_split]$ du -sh .
69G