今天凌晨4點多鐘,在客戶現場的負責人打電話給我,說很奇怪,下載功能時快時慢。此下載功能非常復雜,之前一直是我優化,在半夢半醒中打開電腦,通過遠程看著現場同事在PL/SQL developer中操作。執行同一條SQL,時快時慢,快的時候大概0.6s,慢的時候超過1分鐘。
這條SQL有調用一個函數,功能是動態生成接近200條查詢語句,SQL中都是有綁定變量的。是現場的測試環境,剛剛部署,心想應該不是數據庫負載所致。
1. 抓取數據庫AWR報告,完全沒有壓力,數據庫服務器配置都是槓槓的。此刻心裡有點亂,頭一次遇到這種問題。現場9點鐘要跟客戶演示,此時已經快5點鐘了。
2. 神器出場,打算用10046 trace定位到到底是那條SQL有問題,trace了多次,只有一次是慢的。期間也有插曲,現場不太會用sqlplus,交互化了很多時間。從眾多的SQL中抽絲剝繭,終於定位到SQL,對比是:
SELECT DISTINCT D.ID, D.TABLE_NAME, DCT.COLUMN_NAME, GG.DATA_TYPE,
GG.TECHPARAM_NAME,DCT.SORT_NO FROM GG_CLASSIFY_TECHPARAM DCT, GG_TECHPARAM
GG, GG_CLASSIFY D, REL_OID_CLASSIFY T WHERE DCT.TECHPARAM_ID = GG.ID AND
D.ID = DCT.CLASSIFY_ID AND T.CLASSIFY_ID = D.ID
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 61.00 61.04 0 25968917 0 156
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 61.00 61.04 0 25968917 0 156
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 0 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.80 0.81 0 32461 0 156
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.80 0.81 0 32461 0 156
3. 分析問題,第一感覺是SQL邏輯是否有問題,可惜10046裡面沒有trace到執行計劃,不過看邏輯讀,慢的那次應該是產生了笛卡爾積。經過簡單的檢查,SQL邏輯沒有問題,人的第一感覺不一定靠譜。
4. 我在想是什麼導致執行計劃不准呢,猛然想起REL_OID_CLASSIFY是全局臨時表,快速的想到一種可能,REL_OID_CLASSIFY的統計信息不准導致,通過user_tables查看這張表是沒有統計信息的。那就是每次執行都動態采集啰,在Oracle 11g中執行autotrace,發現level=2,我想試試把動態采樣的級別,說干就干。
SELECT /*+ dynamic_sampling(T 10) */DISTINCT D.ID, D.TABLE_NAME, DCT.COLUMN_NAME, GG.DATA_TYPE,
GG.TECHPARAM_NAME,DCT.SORT_NO FROM GG_CLASSIFY_TECHPARAM DCT, GG_TECHPARAM
GG, GG_CLASSIFY D, REL_OID_CLASSIFY T WHERE DCT.TECHPARAM_ID = GG.ID AND
D.ID = DCT.CLASSIFY_ID AND T.CLASSIFY_ID = D.ID;
發給開發人員,修改相關函數。增量後,多次測試後發現問題解決了。此時已經快7點了,天已經大亮,我有點倦意,但無法再次入睡。
總結:對於這次臨時表的問題,我想問題在於采樣率低了以後造成的惡果。對於全局臨時表要注意兩點,一是要鎖定臨時表收集統計信息的功能,因為你收集的統計信息肯定是錯的;二是使用它時最好是使用動態采用。學習知識,基礎很重要。