如何選擇update merge into

2021-09-24 10:02:22 字數 4439 閱讀 8957

update和merge只用於更新時,倆種方式是可互更換的,但在一些特殊情況下,倆種方式的執行效率差距很大! 

之前oracle sql優化總結 有提到「update和merge的選擇「,在此再例項補充下

update適用於

1、更改單錶速度快穩定性好;

2、某字段即是過濾條件又是更新字段,且該字段有選擇性很強的索引時「update a set status=1 where  id=1 and status=2 and idc in (表)」

merge適用於

1、根據一張表或多表聯合查詢的連線條件對另外一張表進行查詢,連線條件匹配上的進行update,無法匹配的執行insert可直接用merge實現,執行效率要高於insert+update;

2、「update a set i=(select i from b where a.id=b.id) where not exists (select 1 from b where a.id=b.id)」not exists部分需要額外消耗,可以用merge避免;

3、「例子1「 情況

merge缺點:

不支援更改字段放入on【會報錯 ora-38104: 無法更新 on 子句中引用的列: xx】;

有些情況merge 過濾條件不放入on可能會有其他效能問題(例子2、3)

例子1、

sql:

update bill_asn t

set t.source_no =

( select nvl (max(b.wmsnos), '-')

from bill_asn a

inner join bill_syn_out b

on b.sys_no || b.nos = a.bill_no

and a.bizs_type = 4

where a.bill_no = t.bill_no);

執行計畫:

description

object_owner

object_name

cost

cardinality

bytes

update statement, goal = all_rows

3386798772

682546

11603282

update

usr_lmp

bill_asn

table access full

usr_lmp

bill_asn

5520

682546

11603282

sort aggregate154

nested loops

4961

97652704

index range scan

usr_lmp

i_bill_asn_fpno31

16table access full

usr_lmp_jk

bill_syn_out

4958

9957

378366

分析:

該sql執行時間》2小時;更新條目:682546

執行計畫 i_bill_asn_fpno(索引)+bill_syn_out(表) 做 nested loops迴圈每次cardinality=1取一條資料和bill_asn表進行update,這樣的操作執行682546次(錶行數);

cost消耗:682546(錶行) *4961(消耗)=3386110706  接近3386798772

優化方案:

sql:

merge into bill_asn t

using (select nvl( max(b.wmsnos), '-' ) wmsnos, a.bill_no

from bill_asn a

inner join bill_syn_out b

on b.sys_no || b.nos = a.bill_no

and a.bizs_type = 4

group by a.bill_no) t1

on (t1.bill_no = t.bill_no )

when matched then

update set t.source_no = t1.wmsnos;

執行計畫:

description

object_owner

object_name

cost

cardinality

bytes

merge statement, goal = all_rows

20254

66902

1338040

merge

usr_lmp

bill_asn

view

usr_lmp

hash join

20254

66902

19000168

view

usr_lmp

7440

66902

5285258

sort group by

7440

66902

3612708

hash join

6409

97597

5270238

index fast full scan

usr_lmp

i_bill_asn_fpno

1451

66902

1070432

table access full

usr_lmp_jk

bill_syn_out

4955

995696

37836448

table access full

usr_lmp

bill_asn

5520

682546

139921930

** merge 表之間選擇的hash join,且過濾後批量更新~

例子2、

merge 順序:

多表on關聯後[關聯的執行計畫已經選好]--> 篩選where條件...所以就算where取主鍵定值也不會走索引(如下)

原sql:

merge into cs_batch_send_eva eva

using (select order_id, nat_mon from es_ins_rec rec) t

on (t.order_id = eva.order_id )

when matched then

update

set eva.is_legal      = 0 

where eva.batch_send_eva_id = :b1/*主鍵字段*/;

執行計畫:

優化方案:

sql:

merge into cs_batch_send_eva eva

using (select order_id, nat_mon from es_ins_rec rec) t

on (t.order_id = eva.order_id and eva.batch_send_eva_id = :b1/*主鍵字段*/)

when matched then

update

set eva.is_legal      = 0; 

執行計畫:

結果:

由原來的2表全掃,改為走pk_batch_send_eve_id 主鍵 先篩選後是1條記錄,關聯條件t.order_id = eva.order_id使es_ins_rec 也選擇order_id索引。

例子3、

之前遇到過merge 的where 過濾部分寫查詢語句,執行計畫中並沒有體現子查詢語句中關聯的表;

【如圖】

若您sql及執行計畫同例子3的情況,且執行很久都執行不出來,可嘗試將子查詢部分放入on中避免此原因引起的效能問題;

【如圖】

如何選擇網域名稱

一系列的事件讓人們對cn網域名稱投資興致盎然,然而,網域名稱如何註冊?好網域名稱如何起?記者經過多方探訪,總結出cn網域名稱投資的 實用手冊 好網域名稱如何評估 網域名稱的最終價值體現在它是否能帶來流量和利潤,這些結果都將決定你的未來買家願意出多少錢來購買你的網域名稱。所以,衡量乙個網域名稱價值標準...

如何選擇集合

在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法 選擇集合所考慮的關鍵問題在於 效率代價與空間代價的平衡問題。效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。空間代價是指存放的空間消耗記憶體的代價,...

如何選擇集合

在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法 選擇集合所考慮的關鍵問題在於 效率代價與空間代價的平衡問題。效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。空間代價是指存放的空間消耗記憶體的代價,...