Oracle數(shù)據(jù)庫大表更新優(yōu)化記錄

Oracle數(shù)據(jù)庫大表更新優(yōu)化記錄

業(yè)務環(huán)境:為相應根據(jù)國家脫貧攻堅政策兵扬,年底達到完全脫貧的艱巨任務麻裳,全國上下齊心協(xié)力,為這一歷史性艱巨任務砥礪前行器钟。目前以接近尾聲津坑,陜西精準扶貧大數(shù)據(jù)平臺做數(shù)據(jù)抽取和各種統(tǒng)計任務,平臺所具有的特點是數(shù)據(jù)量非常大傲霸,因此在做相關數(shù)據(jù)抽取加上多表關聯(lián)就會導致執(zhí)行速度很慢国瓮,而且非常消耗系統(tǒng)資源。

業(yè)務場景:本次業(yè)務是有關大數(shù)據(jù)平臺將幫扶措施中的9項措施反推更新大戶表中狞谱,著兩個表的數(shù)據(jù)量都特別大乃摹,措施大概有1900萬條數(shù)據(jù),戶表當前年有140萬條數(shù)據(jù)跟衅,歷史大概有800萬條數(shù)據(jù)孵睬。

image.png
image.png

從2020-12-03下午15:00開始執(zhí)行相關查詢并更新

--更新fpxm_type_id值至aa01_2014表中屬性
update aa01_2014 
set fcfs = (select wm_concat(distinct fpxm_type_id) || ','as fpxm_type_id from tbl_fpxm_poor_cs_temp 
where aa01_2014.aaa001 = tbl_fpxm_poor_cs_temp.poor_id 
and tbl_fpxm_poor_cs_temp.data_year = to_char(sysdate,'yyyy') 
group by poor_id,data_year)         --現(xiàn)根據(jù)戶ID分組,在根據(jù)年拼接出這一戶在不同年份享受的政策編碼伶跷,
where exists (select 1 from tbl_fpxm_poor_cs_temp where aa01_2014.aaa001 = tbl_fpxm_poor_cs_temp.poor_id)

結果到第二天早晨來執(zhí)行了1100多分鐘還是沒有執(zhí)行完畢掰读,于是拋棄這個方式。分析原因因為這個更新在查詢有用字段的時候使用兩個表id關聯(lián)叭莫,這就會導致在oracle掃描次數(shù)多達140萬*1900萬次蹈集,100億次之多,執(zhí)行到入土了也可能執(zhí)行不完雇初,于是開始優(yōu)化拢肆。
昨天更新的執(zhí)行報告,what fuck,查看執(zhí)行報告如下:


image.png

優(yōu)化

通過在網(wǎng)上查找資料發(fā)現(xiàn)在更新的時候可以換一種書寫方式少一次對庫的掃描靖诗,
如下:

update customers a   
set    city_name=(select b.city_name from tmp_cust_city b where b.customer_id=a.customer_id)
where  exists (select 1
              from   tmp_cust_city b
              where  b.customer_id=a.customer_id
             )
                 
update (select a.city_name,b.city_name as new_name
            from   customers a,
                   tmp_cust_city b
            where  b.customer_id=a.customer_id
           )
    set    city_name=new_name

但是我沒有使用這個例子郭怪。

我這里采用的是數(shù)據(jù)庫開啟并行執(zhí)行

概念

<html>
一、oracle 并行執(zhí)行
優(yōu)勢:強制啟動并行進程刊橘、分配任務與系統(tǒng)資源鄙才、合并結果集。大大縮短計算時間促绵。在大表查詢等操作中能夠起到良好的效果攒庵。在ODS系統(tǒng)中報表統(tǒng)計等方面更有使用意義。

劣勢:比較消耗資源败晴,不建議在系統(tǒng)超負荷運行的情況下使用浓冒。

注意事項:/+parallel(t,n)/中,t代表表別名或者表明(沒有起別名情況)位衩;n代表進程數(shù)量裆蒸,一般值為:cpu數(shù)量-1熔萧。

例如:SELECT /+parallel(a,16)/ distinct a.comcode FROM statcmain a where a.underwriteenddate BETWEEN DATE'2011-1-1' AND DATE'2014-1-31';
一般而言主要在如下情況使用parallel HINT:

1.表的數(shù)據(jù)量很大,超過一千萬;
2.數(shù)據(jù)庫主機是多個CPU;
3.系統(tǒng)的當前負載較低;
</html>

merge into使用模板

merge into 目標表 a
using 源表 b
on(a.條件字段1=b.條件字段1 and a.條件字段2=b.條件字段2 ……)  
when matched then update set a.更新字段=b.字段
when  not matched then insert into a(字段1,字段2……)values(值1,值2……)
explain plan FOR merge into aa01_2014 a
                 using (select /*+parallel(tbl_fpxm_poor_cs_temp,16)*/ poor_id,wm_concat(distinct fpxm_type_id) || ','as fpxm_type_id 
                        from tbl_fpxm_poor_cs_temp left join aa01_2014 on aa01_2014.aaa001 =tbl_fpxm_poor_cs_temp.poor_id 
                        where tbl_fpxm_poor_cs_temp.data_year = to_char(sysdate,'yyyy') 
                        group by poor_id,data_year) temp
                 on (a.aaa001 = temp.poor_id) 
                 when matched then update set a.fcfs = temp.fpxm_type_id;
--查看執(zhí)行報告
select plan_table_output from TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));

執(zhí)行時間如下圖:
開啟并行執(zhí)行后執(zhí)行報告:


image.png

<html>
結果對比:update和merge into 都更新100億條記錄糖驴,update耗時999:59:59僚祷,邏輯讀消耗2282027;merge into 耗時04.38s贮缕,消耗邏輯讀964.相差太大了辙谜。
其實看著執(zhí)行計劃,這個結果也很容易理解:update采用的類似nested loop的方式感昼,對更新的每一行装哆,都會對查詢的表掃描一次;merge into這里選擇的是hash join定嗓,
則針對每張表都是做了一次 full table scan蜕琴,對每張表都只是掃描一次。
</html>

快速游標方式:
begin
  for tbl_fpxm_poor_cs_temp in (select poor_id,wm_concat(distinct fpxm_type_id) || ','as fpxm_type_id 
          from tbl_fpxm_poor_cs_temp left join aa01_2014 on aa01_2014.aaa001=tbl_fpxm_poor_cs_temp.poor_id
          where tbl_fpxm_poor_cs_temp.data_year = to_char(sysdate,'yyyy') 
          group by poor_id,data_year) loop
          update aa01_2014 set aa01_2014.fcfs = tbl_fpxm_poor_cs_temp.fpxm_type_id where aa01_2014.aaa001=tbl_fpxm_poor_cs_temp.poor_id;
          end loop;
end;

快速游標方式:


image.png

但是這種方式提示wm_concat(distinct fpxm_type_id)連接函數(shù)中不能使用distinct關鍵字宵溅,如圖


image.png

于是修改查詢語句

begin
  for tbl_fpxm_poor_cs_temp in (select poor_id,listagg(fpxm_type_id,',') within group( order by fpxm_type_id) || ',' as fpxm_type_id,data_year from 
                                       (select DISTINCT fpxm_type_id,data_year,poor_id from tbl_fpxm_poor_cs_temp where tbl_fpxm_poor_cs_temp.data_year = to_char(sysdate,'yyyy'))
                                        group by poor_id,data_year) loop
          update aa01_2014 set aa01_2014.fcfs = tbl_fpxm_poor_cs_temp.fpxm_type_id where aa01_2014.aaa001=tbl_fpxm_poor_cs_temp.poor_id;
          end loop;
end;

oracle更新大量數(shù)據(jù)太慢凌简,可以通過游標實現(xiàn)的例子

declare cursor city_cur is
select t.new_customer_id,t.old_customer_id from
citsonline.crm_customer_tmp6 t
where t.new_customer_id!=t.old_customer_id
order by new_customer_id;
begin
for my_cur in city_cur loop

update platform.crm_service_customer_bak s
set s.customer_id=my_cur.new_customer_id
where s.customer_id=my_cur.old_customer_id;

/** 此處也可以單條/分批次提交,避免鎖表情況 **/
if mod(city_cur%rowcount,1000)=0 then
dbms_output.put_line('----');
commit;
end if;
end loop;
commit;
end;

根據(jù)案例修改后的語句

declare cursor fpxm_cur is
               select /*+parallel(tbl_fpxm_poor_cs_temp,16)*/ poor_id,
                      listagg(fpxm_type_id,',') within group( order by fpxm_type_id) || ',' as fpxm_type_id,
                      data_year
               from 
                  --去除重復
                 (select DISTINCT fpxm_type_id,data_year,poor_id from tbl_fpxm_poor_cs_temp where  tbl_fpxm_poor_cs_temp.data_year = to_char(sysdate,'yyyy'))
               group by poor_id,data_year;
begin for tbl_fpxm_poor_cs_temp in fpxm_cur loop
          update aa01_2014 set aa01_2014.fcfs = tbl_fpxm_poor_cs_temp.fpxm_type_id where aa01_2014.aaa001=tbl_fpxm_poor_cs_temp.poor_id;
          /** 此處也可以單條/分批次提交恃逻,避免鎖表情況 **/
          if mod(fpxm_cur%rowcount,1000)=0 then
          dbms_output.put_line('----');
          commit;
          end if;
          end loop;
          commit;
end;
image.png

可以看出執(zhí)行速度是相當可觀雏搂,但是如果同時去掉并行執(zhí)行速度更快3s不知道為啥。
如下圖:


image.png

案例

這今天在研究kettle工具寇损,是一款國外純java開發(fā)的開源ETL工具凸郑,抽取數(shù)據(jù)確實非常方便,大家有空可以去下載下來試試看矛市,方便之處在于它不用安裝芙沥,解壓完了就能直接用了(必須提前配置jdk和jre環(huán)境到系統(tǒng)環(huán)境中)。今天要說的不是這款軟件浊吏,問題是由使用這個軟件引起的憨愉,我在抽取數(shù)據(jù)后需要完成一個更新操作語句如下:

update case_person_saxx a set a.case_id=(select id from case_xzcf b where b.app_id = a.app_id) ;

update invole_case_unit_saxx a set a.case_id=(select id from case_xzcf b where b.app_id = a.app_id)卿捎;

上面的語句中case_person_saxx表和case_xzcf 表中數(shù)據(jù)量大概在16萬條左右配紫,說起來也不是特別大,但是這個語句執(zhí)行起來特別的慢午阵,我等了半個多小時都沒執(zhí)行完躺孝,后來建索引稍微快一點,在網(wǎng)上找到一種更快捷的更新語句(因為我數(shù)據(jù)庫基礎不好很多語句不熟悉底桂,呵呵植袍!大神來看到了別笑話我就行!)如下:

merge into case_person_saxx t
using (select max(id) as id, app_id from case_xzcf group by app_id) s
on (t.app_id = s.app_id)
when matched then
  update set t.case_id = s.id;


  merge into invole_case_unit_saxx t
using (select max(id) as id, app_id from case_xzcf group by app_id) s
on (t.app_id = s.app_id)
when matched then
  update set t.case_id = s.id;

記言:如果你的才華不能匹配你的野心籽懦,請努力于个!

參考文獻:

一、
<html>
執(zhí)行報告分析:

explain plan FOR select 1 from dual;

select plan_table_output from TABLE(DBMS_XPLAN.DISPLAY('PLAN_TABLE'));
</html>
二暮顺、快速游標法

快速游標法

方式二

三厅篓、merge into 和單個update 執(zhí)行效率分析

merge into 和單個update 執(zhí)行效率分析

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末秀存,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子羽氮,更是在濱河造成了極大的恐慌或链,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件档押,死亡現(xiàn)場離奇詭異澳盐,居然都是意外死亡,警方通過查閱死者的電腦和手機令宿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門叼耙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人粒没,你說我怎么就攤上這事旬蟋。” “怎么了革娄?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵倾贰,是天一觀的道長。 經(jīng)常有香客問我拦惋,道長匆浙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任厕妖,我火速辦了婚禮首尼,結果婚禮上,老公的妹妹穿的比我還像新娘言秸。我一直安慰自己软能,他們只是感情好,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布举畸。 她就那樣靜靜地躺著查排,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抄沮。 梳的紋絲不亂的頭發(fā)上跋核,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天,我揣著相機與錄音叛买,去河邊找鬼砂代。 笑死,一個胖子當著我的面吹牛率挣,可吹牛的內容都是我干的刻伊。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼捶箱!你這毒婦竟也來了智什?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤讼呢,失蹤者是張志新(化名)和其女友劉穎撩鹿,沒想到半個月后谦炬,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體悦屏,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年键思,在試婚紗的時候發(fā)現(xiàn)自己被綠了础爬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡吼鳞,死狀恐怖看蚜,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情赔桌,我是刑警寧澤供炎,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站疾党,受9級特大地震影響音诫,放射性物質發(fā)生泄漏。R本人自食惡果不足惜雪位,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一竭钝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雹洗,春花似錦香罐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至螃成,卻和暖如春港令,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背锈颗。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工顷霹, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人击吱。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓淋淀,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子朵纷,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容