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網域名稱投資的 實用手冊 好網域名稱如何評估 網域名稱的最終價值體現在它是否能帶來流量和利潤,這些結果都將決定你的未來買家願意出多少錢來購買你的網域名稱。所以,衡量乙個網域名稱價值標準...
如何選擇集合
在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法 選擇集合所考慮的關鍵問題在於 效率代價與空間代價的平衡問題。效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。空間代價是指存放的空間消耗記憶體的代價,...
如何選擇集合
在程式設計的過程中,選擇何種集合至關重要,下面由我來總結下選擇集合的方法 選擇集合所考慮的關鍵問題在於 效率代價與空間代價的平衡問題。效率代價是指執行的效率,簡單的說如果乙個資源沒有把索引記錄下來,那麼要找到他你就需要執行程式,那麼你的代價在於系統花錢了時間。空間代價是指存放的空間消耗記憶體的代價,...