excel數(shù)據(jù)導(dǎo)出sql優(yōu)化(一)

excel數(shù)據(jù)導(dǎo)出sql優(yōu)化分2篇纳寂,本文有sql優(yōu)化篇

假設(shè)有A,B,C,D,E5張表主穗,需要導(dǎo)出這5張表的部分信息,查詢條件只涉及到A,B,C的相關(guān)字段,約定A,B,C,D,E對(duì)應(yīng)關(guān)系都為1對(duì)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表主鍵)
如何導(dǎo)出忽媒?
1 簡(jiǎn)單的實(shí)現(xiàn)步驟如下:
1>left join A.B.C,獲得ABC的相關(guān)信息.

<select id="getABC" ......>
    select  *  from A left join B on A.ID  = B.AID
    left join C on C.BID = B.AID and C.AID = B.AID
    <where>
      <if test="TYPEA != NULL  and TYPEA!=''">
        and A.TYPEA = #{TYPEA}
      </if>
     <if test="TYPEB != NULL and TYPEB!='' ">
        and B.TYPEB = #{TYPEB}
      </if>
     <if test="NAMEC!= NULL and NAMEC !='' ">
        and C.NAMEC   CONCAT('%','${NAMEC}','%' )
      </if>
    </where>
</select>

2>循環(huán)獲得DE數(shù)據(jù)晦雨,然后在組裝excel信息

/** 偽代碼 **/
public void getABCDEList(ABC abc) {
    List<ABCDE> resultList = new ArrayList<>();
    List<ABC> 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 根據(jù)abc,d,e組裝abcde數(shù)據(jù)
        resultList.add(abcde);
    }
    //TODO excel一次性寫入skip,resultList
}

初看起來,也沒什么問題隘冲,但是當(dāng)數(shù)據(jù)量快速增漲的時(shí)候闹瞧,發(fā)現(xiàn)excel導(dǎo)出的時(shí)間會(huì)比較慢,而且當(dāng)數(shù)據(jù)條數(shù)過W的時(shí)候展辞,甚至?xí)霈F(xiàn)導(dǎo)出空頁的情況奥邮。
其實(shí)這種簡(jiǎn)單的寫法有3個(gè)問題:
1>一次性導(dǎo)出數(shù)據(jù)可能會(huì)OOM,換成分批寫入excel
2>left join效率低下,尤其是2張表以上,select * 的寫法應(yīng)該具體到對(duì)應(yīng)的字段
3>for循環(huán)獲取數(shù)據(jù)會(huì)循環(huán)調(diào)用sql,執(zhí)行時(shí)間長(zhǎng)
針對(duì)上述3個(gè)問題我們做進(jìn)一步的優(yōu)化洽腺,稱為優(yōu)化版本:
1> 針對(duì)sql條件我們做優(yōu)化脚粟,拆分為2個(gè)查詢方法核无,并且加上分頁,去掉*用法,left join去掉
方法一: getAB

<select id="getAB" ......>
   select  A.ID as AID,A.TYPEA,A.NAMEA,
   B.ID as BID, B.TYPEB,B.NAMEB from 
  A , B  
   <where>
     AND A.ID  = B.AID
     <if test="TYPEA != NULL  and TYPEA!=''">
       and A.TYPEA = #{TYPEA}
     </if>
    <if test="TYPEB != NULL and TYPEB!='' ">
       and B.TYPEB = #{TYPEB}
     </if>
   </where>
order by A.ID desc
limit #{skip},#{limit}
</select>

方法二:getABC

<select id="getABC" ......>
    select  A.ID as AID,A.TYPEA,A.NAMEA,
   B.ID as BID, B.TYPEB,B.NAMEB ,
  C.ID as CID, C.TYPEC,C.NAMEC ,
  from A,B,C
  from A left join B on 
  left join C on 
    <where>
       and A.ID  = B.AID
       and C.BID = B.AID 
      and C.AID = B.AID
      <if test="TYPEA != NULL  and TYPEA!=''">
        and A.TYPEA = #{TYPEA}
      </if>
     <if test="TYPEB != NULL and TYPEB!='' ">
        and B.TYPEB = #{TYPEB}
      </if>
     <if test="NAMEC!= NULL and NAMEC !='' ">
        and C.NAMEC   CONCAT('%','${NAMEC}','%' )
      </if>
    </where>
  order by A.ID desc
  limit #{skip},#{limit}
</select>

2>循環(huán)自分頁獲取數(shù)據(jù)

/** 偽代碼 **/
public void  getABCDEList(ABC abc) {
    List<ABCDE> resultList = new ArrayList<>();
    List<ABC> listABC = new ArrayList<>();
   //是否需要獲取C信息
    boolean needC =true;
    //對(duì)比測(cè)試50藕坯,100团南,200,300霹购,400佑惠,500,1000條齐疙,發(fā)現(xiàn)200效果更佳執(zhí)行
    //總時(shí)間最短
    int skip = 0;
    int limit = 200; 
    int pageNum = 1;
    boolean hasNext = true;
    while(hasNext) {
        //NAMEC存在
        skip = (pageNum - 1) * limit;
        //根據(jù)查詢條件調(diào)用對(duì)應(yīng)的方法
        if(null != abc.NAMEC  && "".equls(abc.NAMEC)) {
         listABC = ABCMapper.getABCList(abc,skip,limit);
         needC = false;
       } else {
         listABC = ABCMapper.getABList(abc, skip,limit);
       }
      //調(diào)用批量獲取list方法
      resultList = getABCDEList(listABC);
     //TODO excel分批次寫入文件
    if(listABC.size()  <  limit)
       hasNext = false;
   } else {
     //分頁自動(dòng)加1
      pageNum += 1;
  }
    return resultList;
}

方法二:根據(jù)listABC獲得List<ABCDE>

private List<ABCDE>  getABCDEList(List<ABC> listABC){
  //循環(huán)獲取A.B 對(duì)應(yīng)ID信息
      List<Integer> AIDS = new ArrayList<>();
      List<Integer> BIDS = new ArrayList<>();
     for(ABC abc:listABC) {
        AIDS.add(abc.AID);
        BIDS.add(abc.BID);
     }
    // 批量獲取C.D.E數(shù)據(jù)
     List<C> listC = new ArrayList<>();
     List<D> listD = new ArrayList<>();
     List<E> listE = new ArrayList<>();
     //按照AID+BID放置到對(duì)應(yīng)的map結(jié)構(gòu)里
     Map<String,C> mapC = new HashMap<>();
     Map<String,D> mapD = new HashMap<>();
     Map<String,E> mapE = new HashMap<>();
     //數(shù)據(jù)獲取和組裝
      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 根據(jù)CDE 對(duì)應(yīng)ID
    for(ABC abc:listABC){
        ABCDE abcde = new ABCDE();
        //TODO 根據(jù)abc,(mapC),mapD,mapE裝abcde數(shù)據(jù)
        resultList.add(abcde);
    }
   return resultList;
}

后記:關(guān)于excel寫入分批寫入的優(yōu)化,會(huì)開專門的篇幅概述赌厅,敬請(qǐng)期待轿塔!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末勾缭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毒嫡,更是在濱河造成了極大的恐慌兜畸,老刑警劉巖碘梢,帶你破解...
    沈念sama閱讀 211,423評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件煞躬,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡龄坪,警方通過查閱死者的電腦和手機(jī)健田,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,147評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門妓局,熙熙樓的掌柜王于貴愁眉苦臉地迎上來呈宇,“玉大人,你說我怎么就攤上這事存炮◎诶欤” “怎么了?”我有些...
    開封第一講書人閱讀 157,019評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵享完,是天一觀的道長(zhǎng)般又。 經(jīng)常有香客問我茴迁,道長(zhǎng)句狼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,443評(píng)論 1 283
  • 正文 為了忘掉前任胳螟,我火速辦了婚禮糖耸,結(jié)果婚禮上丘薛,老公的妹妹穿的比我還像新娘。我一直安慰自己舍扰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,535評(píng)論 6 385
  • 文/花漫 我一把揭開白布陵且。 她就那樣靜靜地躺著慕购,像睡著了一般茬底。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阱表,一...
    開封第一講書人閱讀 49,798評(píng)論 1 290
  • 那天捶枢,我揣著相機(jī)與錄音,去河邊找鬼谨胞。 笑死蒜鸡,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叶沛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,941評(píng)論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼灰署,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼溉箕!你這毒婦竟也來了悦昵?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,704評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤寡痰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后连躏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贞滨,經(jīng)...
    沈念sama閱讀 44,152評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,494評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尤蒿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片幅垮。...
    茶點(diǎn)故事閱讀 38,629評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡忙芒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出呵萨,到底是詐尸還是另有隱情,我是刑警寧澤囱皿,帶...
    沈念sama閱讀 34,295評(píng)論 4 329
  • 正文 年R本政府宣布嘱腥,位于F島的核電站,受9級(jí)特大地震影響齿兔,放射性物質(zhì)發(fā)生泄漏础米。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,901評(píng)論 3 313
  • 文/蒙蒙 一组砚、第九天 我趴在偏房一處隱蔽的房頂上張望糟红。 院中可真熱鬧艾帐,春花似錦柒爸、人聲如沸事扭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罐农。三九已至,卻和暖如春宰睡,著一層夾襖步出監(jiān)牢的瞬間气筋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,978評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工麸恍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留搀矫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,333評(píng)論 2 360
  • 正文 我出身青樓采够,卻偏偏與公主長(zhǎng)得像蹬癌,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子逝薪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,499評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容