excel数据导出sql优化分2篇,本文有sql优化篇
假设有A,B,C,D,E5张表,需要导出这5张表的部分信息,查询条件只涉及到A,B,C的相关字段,约定A,B,C,D,E对应关系都为1对1.
A表字段:ID,TYPEA,NAMEA....;
B表字段:ID,AID,TYPEB,NAMEB...;(AID为A表主键)
C表字段: ID,AID,BID,TYPEC,NAMEC...;(AID为A表主键,BID为B表主键)
D表字段:ID,AID,BID,TYPED,NAMED...;(AID为A表主键,BID为B表主键)
E表字段:ID,AID,BID,TYPEE,NAMEE...;(AID为A表主键,BID为B表主键)
如何导出?
1 简单的实现步骤如下:
1>left join A.B.C,获得ABC的相关信息.
2>循环获得DE数据,然后在组装excel信息
/** 伪代码 **/
public void getABCDEList(ABC abc) {
List resultList = new ArrayList<>();
List listABC = ABCMapper.getABCList(ABC abc);
for(ABC abc:listABC){
D d = DMappger.getDByID(abc.AID, abc.BID);
E e = EMappger.getDByID(abc.AID, abc.BID);
ABCDE abcde = new ABCDE();
//TODO 根据abc,d,e组装abcde数据
resultList.add(abcde);
}
//TODO excel一次性写入skip,resultList
}
初看起来,也没什么问题,但是当数据量快速增涨的时候,发现excel导出的时间会比较慢,而且当数据条数过W的时候,甚至会出现导出空页的情况。
其实这种简单的写法有3个问题:
1>一次性导出数据可能会OOM,换成分批写入excel
2>left join效率低下,尤其是2张表以上,select * 的写法应该具体到对应的字段
3>for循环获取数据会循环调用sql,执行时间长
针对上述3个问题我们做进一步的优化,称为优化版本:
1> 针对sql条件我们做优化,拆分为2个查询方法,并且加上分页,去掉*用法,left join去掉
方法一: getAB
方法二:getABC
2>循环自分页获取数据
/** 伪代码 **/
public void getABCDEList(ABC abc) {
List resultList = new ArrayList<>();
List listABC = new ArrayList<>();
//是否需要获取C信息
boolean needC =true;
//对比测试50,100,200,300,400,500,1000条,发现200效果更佳执行
//总时间最短
int skip = 0;
int limit = 200;
int pageNum = 1;
boolean hasNext = true;
while(hasNext) {
//NAMEC存在
skip = (pageNum - 1) * limit;
//根据查询条件调用对应的方法
if(null != abc.NAMEC && "".equls(abc.NAMEC)) {
listABC = ABCMapper.getABCList(abc,skip,limit);
needC = false;
} else {
listABC = ABCMapper.getABList(abc, skip,limit);
}
//调用批量获取list方法
resultList = getABCDEList(listABC);
//TODO excel分批次写入文件
if(listABC.size() < limit)
hasNext = false;
} else {
//分页自动加1
pageNum += 1;
}
return resultList;
}
方法二:根据listABC获得List
private List getABCDEList(List listABC){
//循环获取A.B 对应ID信息
List AIDS = new ArrayList<>();
List BIDS = new ArrayList<>();
for(ABC abc:listABC) {
AIDS.add(abc.AID);
BIDS.add(abc.BID);
}
// 批量获取C.D.E数据
List listC = new ArrayList<>();
List listD = new ArrayList<>();
List listE = new ArrayList<>();
//按照AID+BID放置到对应的map结构里
Map mapC = new HashMap<>();
Map mapD = new HashMap<>();
Map mapE = new HashMap<>();
//数据获取和组装
if(needC){
listC = CMapper.getListCByIDS(AIDS,BIDS);
for(C c:listC) {
mapC.put(String.valueOf(c.AID) + "-" + String.valueOf(c.AID),c);
}
}
listD = DMapper.getListCByIDS(AIDS,BIDS);
listE = EMapper.getListCByIDS(AIDS,BIDS);
for(D d:listD) {
mapD.put(String.valueOf(d.AID) + "-" + String.valueOf(d.AID),d);
}
for(E e:listE) {
mapE.put(String.valueOf(e.AID) + "-" + String.valueOf(e.AID),e);
}
//TODO 根据CDE 对应ID
for(ABC abc:listABC){
ABCDE abcde = new ABCDE();
//TODO 根据abc,(mapC),mapD,mapE装abcde数据
resultList.add(abcde);
}
return resultList;
}
后记:关于excel写入分批写入的优化,会开专门的篇幅概述,敬请期待!