SQL語句(0kym2mpab9k16):
SELECT COUNT(*)
FROM TF_BH_TRADE_CBSS A
WHERE A.TRADE_TYPE_CODE IN ('141', '142')
AND A.USER_ID = :B2
AND A.ACCEPT_DATE > :B1
AND A.SUBSCRIBE_STATE = '9'
我們從1号早上的AWR報告中看到這條語句開銷非常大,初看之,這麼簡單的一條語句,從理論上來講應當沒什麼問題,也不存在可優化的地方。仔細看一下報告,卻可以發現,這條語句執行的次數并不多,才4500次,但是每次執行的gets卻非常大,達到了51萬。
如果我們參照語句的業務邏輯來了解一下,這個語句應當是根據user_id來進行統計,而每個user_id是應該有索引的,并且每個user_id對應的行數應該也是非常有限的。按照經驗來推斷,SQL執行的gets開銷應該在幾百以内,不應該上千,更不應該上萬了。那應該是執行計劃出問題了。
那接下來我們來看看執行計劃:
select dbms_xplan.display_awr('0kym2mpab9k16') from dual ;
這下子比較明顯了,有兩個不同的執行計劃,分别走了兩個不同的索引,從索引的名字上也可以判斷,一個走了user_id,一個走了acceptdate。那基本可以确定了,這個語句的問題就在于錯用了accept_date字段上的索引,accept_date的選擇性比較低,導緻了大量的開銷。
那如何解決呢?
1、優先應該考慮的是重新收集統計資訊,相信Oracle在絕大部分情況下都是可以得出高效的執行計劃的。很多這種情況是由于統計資訊陳舊或者錯誤誤導了Oracle,得到了錯誤的執行計劃。
2、使用強制索引,然後更新重新釋出代碼
SELECT COUNT(*)
FROM TF_BH_TRADE_CBSS A
WHERE A.TRADE_TYPE_CODE IN ('141', '142')
AND A.USER_ID = :B2
AND A.ACCEPT_DATE > :B1
AND A.SUBSCRIBE_STATE = '9'
3、其他方式固定執行計劃。