這是某客戶關鍵系統的一個TOP SQL:
sql
INSERT INTO /*+ append */ TF_B_OCS_BATDEAL (...... )性能優化
SELECT F_SYS_GETSEQID(EPARCHY_CODE, 'batch_id')微信
......session
FROM TF_F_USER B併發
WHERE B.REMOVE_TAG = '0' AND USER_ID = :B1 AND B.USER_STATE_CODESET = '0' AND oracle
LENGTH(SERIAL_NUMBER) = '11' AND SERIAL_NUMBER LIKE '1%' AND app
NOT EXISTS 性能
(優化
SELECT 1spa
FROM TF_F_USER_SHARE_RELA C
WHERE B.USER_ID = C.USER_ID_B AND C.END_DATE > SYSDATE
);
根據下圖sqlhc獲取的信息,該SQL平均每次插入不到一條記錄,每半小時執行10萬次左右。
爲何cpu時間消耗不多,大部分等待時間是application等待?
sqlhc裏面也有交待:
這些wait class是application的具體等待事件是enq:TM - contention,也就是表鎖。在AWR報告的TOP 10事件中,也出現了這個事件,並且佔DB time的4.6%,可見一個SQL就對系統形成了較大的影響:
這個表鎖是如何生成的?
罪魁禍首就是SQL中使用的append Hint。
append的Hint通常使用在insert select語句,插入大量結果集的時候,採用直接路徑(direct path)在表的高水位線以上直接寫入數據。在沒有commit以前,sql會一直持有表鎖。
這個Hint在數據倉庫的SQL中使用較多,一次插入記錄幾十萬以上,執行頻率低。
可是,在本例OLTP系統中,頻繁執行並且插入少許記錄的SQL也使用了append的hint,形成的後果就是:
一、sql執行效率低,大量的表鎖等待,併發越多等待越嚴重。
二、插入的表TF_B_OCS_BATDEAL,有大量的空間被浪費,每插入一條記錄都會佔用一個block。並且即便有大量記錄被delete,這些高水位線如下的空閒塊不會被從新使用。
解決方法:
這種頻繁執行,每次插入少許記錄的狀況,不能使用append,必須立刻去掉這個hint。
補充:
並行DML開啓時,默認啓用append插入模式。
insert /*+ parallel(4) */ into xxx select ....
這個SQL默認並無開啓並行DML,只是後面的select部分使用了並行,這種狀況沒有使用append。
alter session enable parallel dml; --啓用並行DML
insert /*+ parallel(4) */ into xxx select
這時就啓用了並行DML,不加append的hint,默認也是append插入模式。
本文分享自微信公衆號 - 老虎劉談oracle性能優化(sql_tigerliu)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。