一次ORA-4030問題診斷及解決(三)
在報表資料庫的後臺alert檔案中發現了這個錯誤,簡單記錄一下問題的診斷和解決過程。資料庫版本9204 for Solaris sparc64。
尋找產生問題的真正原因。
一次ORA-4030問題診斷及解決(一):http://yangtingkun.itpub.net/post/468/469922
一次ORA-4030問題診斷及解決(二):http://yangtingkun.itpub.net/post/468/469965
在第一篇文章中,定位了問題並且找到了解決方法;在第二篇文章中,找到了導致源資料庫和目標資料庫執行計劃不同的原因。
但是到目前為止,還沒有找到這個問題產生的真正原因。
首先理一下思路,根據第一篇文章的描述,產生ORA-4030問題的原因是由於一個大資料量的插入語句選擇了一個十分糟糕的執行計劃。而導致Oracle選擇了這個執行計劃的直接原因是由於列的統計資訊出現了錯誤。而在第二篇文章中,可以確認由於源資料庫的版本為9201,沒有使用列統計資訊中的DENSITY列,所以沒有引發這個問題。而在目標資料庫版本為9204,Oracle使用了統計資訊列DENSITY的值,所以Oracle認為訪問ORD_HIT_COMM表且透過ENABLE_FLAG列進行限制,只會返回1條記錄,這就導致了Oracle產生了一個錯誤的離譜的執行計劃。
現在的問題是什麼導致了源資料庫錯誤統計資訊的產生。
這就需要檢查源資料庫資料和統計的來源。因為在源資料庫9201上直接收集統計資訊,是不會得到這種DENSITY的。
經過檢查發現這個9201的源資料庫仍然不是資料的真正源頭,而真正的來源資料庫版本是10203。
發現了這個資訊,那麼問題的產生就不奇怪了。
看一下10203上這張表的統計資訊:
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS, HISTOGRAM
2 FROM USER_TAB_COLUMNS
3 WHERE TABLE_NAME = 'ORD_HIT_COMM'
4 AND COLUMN_NAME = 'ENABLE_FLAG';
COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS HISTOGRAM
------------ ------------ ---------- ---------- ----------- ---------------
ENABLE_FLAG 2 0 2.8355E-07 2 FREQUENCY
可以看到,在Oracle10g使用了BUCKETS的設定,而且USER_TAB_COLUMNS新增了一個欄位HISTOGRAM用來表示列的統計資訊的型別。
FREQUENCY型別和以往的HEIGHT BALANCED類似的列統計不同。使用FREQUENCY型別,Oracle會選擇與NUM_DISTINCT相同數量的NUM_BUCKETS來進行直方圖統計,而直方圖統計資訊方式和基於高度的統計資訊是不同的。最關鍵的是,這種統計方式的DENSITY的結果和HEIGHT BALANCED的計算方式大不相同。
因此在10g中,由於Oracle瞭解當前列的統計資訊方式為FREQUENCY型別,因此可以根據直方圖的資訊得到正確的執行計劃和返回記錄數:
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS, HISTOGRAM
2 FROM USER_TAB_COLUMNS
3 WHERE TABLE_NAME = 'ORD_HIT_COMM'
4 AND COLUMN_NAME = 'ENABLE_FLAG';
COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS HISTOGRAM
------------ ------------ ---------- ---------- ----------- ---------------
ENABLE_FLAG 2 0 2.8355E-07 2 FREQUENCY
1 row selected.
SQL> EXPLAIN PLAN FOR
2 SELECT * FROM ORD_HIT_COMM WHERE ENABLE_FLAG = '1';
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------
-----------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
-----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1691K| 1200M| 34103 (2)|
| 1 | TABLE ACCESS FULL| ORD_HIT_COMM | 1691K| 1200M| 34103 (2)|
-----------------------------------------------------------------------
11 rows selected.
但是如果將統計資訊匯入到920資料庫中,就會存在嚴重的問題。由於9i的資料庫中沒有表示統計資訊型別的HISTOGRAM列,因此即使是基於FREQUENCY型別的統計資訊,也會被當作基於HEIGHT BALANCED型別的統計資訊。
而且從920匯入的統計資訊可以看到,雖然直方圖的統計資訊被匯入,但是USER_TAB_COLUMNS中的NUM_BUCKETS列的值為1,也就是說920中最佳化器根本不會去考慮直方圖資訊,而是直接透過NUM_DISTINCT和DENSITY的值來確定執行計劃和返回記錄數。
對於9201版本,Oracle都使用NUM_DISTINCT的值,也就避免了問題的產生。而在9204中,Oracle使用了DENSITY的值,而這個值並不是9204版本的DBMS_STATS包生成的統計資訊,而是從10g環境中匯入的,且這個值在10g的FREQUENCY型別的統計資訊中已經改變了計算方法,使得計算結果比920環境中要小得多,從而導致了9204上錯誤執行計劃的產生。
顯然,整個問題完全是由於版本差異造成的。這個問題說明在將10g的表匯入到920環境中,最好不要匯入統計資訊。
在匯出階段或在匯入階段設定STATISTICS = NONE,避免10g的統計資訊匯入到920環境中,在匯入過程結束後,手工在920環境上重新收集統計資訊。
一旦10g的統計資訊被匯入到920環境中,就必須重新收集統計資訊:
SQL> SELECT * FROM V$VERSION;
BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.4.0 - 64bit Production
PL/SQL Release 9.2.0.4.0 - Production
CORE 9.2.0.3.0 Production
TNS for Linux: Version 9.2.0.4.0 - Production
NLSRTL Version 9.2.0.4.0 - Production
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS
2 FROM USER_TAB_COLUMNS
3 WHERE TABLE_NAME = 'ORD_HIT_COMM'
4 AND COLUMN_NAME = 'ENABLE_FLAG';
COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS
------------------------------ ------------ ---------- ---------- -----------
ENABLE_FLAG 2 0 2.8355E-07 1
SQL> EXPLAIN PLAN FOR
2 SELECT * FROM ORD_HIT_COMM WHERE ENABLE_FLAG = '1';
已解釋。
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
----------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 744 | 9817 |
|* 1 | TABLE ACCESS FULL | ORD_HIT_COMM | 1 | 744 | 9817 |
----------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ORD_HIT_COMM"."ENABLE_FLAG"='1')
Note: cpu costing is off
已選擇14行。
這時10g的統計資訊已經匯入到9204環境中,如果忘記重新收集統計資訊就會導致這個錯誤的產生:
SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'ORD_HIT_COMM')
PL/SQL 過程已成功完成。
SQL> SELECT COLUMN_NAME, NUM_DISTINCT, NUM_NULLS, DENSITY, NUM_BUCKETS
2 FROM USER_TAB_COLUMNS
3 WHERE TABLE_NAME = 'ORD_HIT_COMM'
4 AND COLUMN_NAME = 'ENABLE_FLAG';
COLUMN_NAME NUM_DISTINCT NUM_NULLS DENSITY NUM_BUCKETS
------------------------------ ------------ ---------- ---------- -----------
ENABLE_FLAG 2 0 .5 1
SQL> EXPLAIN PLAN FOR
2 SELECT * FROM ORD_HIT_COMM WHERE ENABLE_FLAG = '1';
已解釋。
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------
----------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost |
----------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 889K| 632M| 8932 |
|* 1 | TABLE ACCESS FULL | ORD_HIT_COMM | 889K| 632M| 8932 |
----------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("ORD_HIT_COMM"."ENABLE_FLAG"='1')
Note: cpu costing is off
已選擇14行。
這個問題也從另一個角度說明,進行跨版本遷移,測試工作的重要性。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4227/viewspace-440594/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 診斷並解決 ORA-4030 錯誤 (文件 ID 1548826.1)
- 診斷並解決 ORA-4030 錯誤 (Doc ID 1548826.1)
- ora-4031(ora-4030)診斷分析ora-4031(ora-4030)診斷分析
- 一次gc buffer busy問題的診斷GC
- 一次網路問題的診斷(二)
- SQL問題診斷SQL
- 重啟listener解決的ora-4030問題
- Oracle診斷工具 - ORA-4030 Troubleshooting ToolOracle
- 如何診斷和解決db2問題DB2
- 診斷並解決 IBMLotusDomino8 郵件路由問題IBM路由
- enq: HW - contention診斷及解決過程ENQ
- 記一次使用gdb診斷gc問題全過程GC
- .記一次使用gdb診斷gc問題全過程GC
- GreysJava線上問題診斷工具Java
- 問題診斷和PLSQL方面SQL
- 快取三大問題及解決方案快取
- 一次異常記憶體消耗的診斷與解決記憶體
- WebSphere Application Server 常見問題及解答:故障診斷WebAPPServer
- RAC系統的問題診斷最佳實踐,及常見問題分析
- eMarketer:消費者線上尋求健康問題解決方法和診斷工具
- 診斷和解決CPU利用率高的問題(zt)
- GC BUFFER BUSY問題的診斷GC
- 使用crsctl工具診斷cluster問題
- Oracle學習遇到的問題收集及解決 - 不斷更新Oracle
- 使用MTR命令診斷網路問題
- Oracle Stream實戰(10)—問題診斷Oracle
- Oracle效能問題診斷一例Oracle
- 5種常見的 DNS 故障診斷及問題處理方法DNS
- 熊貓大俠一次效能診斷優化十一問優化
- Oracle效能問題 - 常用查詢診斷及調整指令碼[不斷更新] (final)Oracle指令碼
- 詳解JAVA執行緒問題診斷工具Thread DumpJava執行緒thread
- 一次RAC VIP漂移的結果診斷及修復
- 在Linux中,如何診斷和解決系統啟動問題?Linux
- 快取世界中的三大問題及解決方案快取
- 問題解決方法有三
- Windows解決斷後佔用問題Windows
- 常見問題及解決
- Timesten問題診斷手冊總結