這幾天測試java內存數據庫,和oracle比較時發下一個update from語句很慢,如下:
update business_new set fare1_balance_ratio = (select BALANCE_RATIO from bfare2 where bfare2.exchange_type = business_new.exchange_type and bfare2.stock_type = business_new.stock_type and (bfare2.entrust_way = business_new.entrust_way) and (bfare2.entrust_type = business_new.entrust_type) and bfare2.fare_type = '0')
執行計划是這樣的:
從執行計划可以看出,走的就是nl關聯,所以慢是正常的。
於是將其改寫為merge,如下:
merge into business_new using bfare2 on (bfare2.exchange_type = business_new.exchange_type and bfare2.stock_type = business_new.stock_type and (bfare2.entrust_way = business_new.entrust_way) and (bfare2.entrust_type = business_new.entrust_type) and bfare2.fare_type = '4') when matched then update set business_new.farex_balance_ratio = bfare2.BALANCE_RATIO
改寫后執行計划如下:
很快就跑出來了。需要注意的是,update語句本身是通過hint讓兩表強制走hash join的。
除了用merge改寫讓兩表關聯走hash join外,還有一種更優、但有條件的做法。如下:
update (select fare1_balance_ratio,BALANCE_RATIO from business_new,bfare2 where bfare2.exchange_type = business_new.exchange_type and bfare2.stock_type = business_new.stock_type and (bfare2.entrust_way = business_new.entrust_way) and (bfare2.entrust_type = business_new.entrust_type) and bfare2.fare_type = '0') set fare1_balance_ratio = BALANCE_RATIO ;
這也稱為inline view更新法,性能是最好的,但相比merge並不明顯。但表B的主鍵一定要在where條件中,並且是以“=”來關聯被更新表,否則會遇到ORA-01779: 無法修改與非鍵值保存表對應的列。造成這個錯誤的原因是更新的列不是事實表的列,而是維度表的列。換句話說,如果兩張表關聯,其中一張表的關聯列是主鍵,那么另一張表就是事實表,也就是說另一張表中的列就是可更新的;除非另一張表的關聯列也是主鍵,否則這張表就是不可更新的,如果更新語句涉及到了這張表,就會出現ORA-1799錯誤。也就是,要么兩張表都通過PK關聯,要么只有非PK這張表可更新。
至於for循環,乖乖,除非邏輯特別復雜,用for bulk collect,否則不要考慮。