一次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/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 一次gc buffer busy問題的診斷GC
- SQL問題診斷SQL
- 如何診斷和解決db2問題DB2
- 記一次使用gdb診斷gc問題全過程GC
- .記一次使用gdb診斷gc問題全過程GC
- 快取三大問題及解決方案快取
- 詳解JAVA執行緒問題診斷工具Thread DumpJava執行緒thread
- 在Linux中,如何診斷和解決系統啟動問題?Linux
- 診斷叢集的潛在問題
- 使用MTR命令診斷網路問題
- 5種常見的 DNS 故障診斷及問題處理方法DNS
- 記一次Razor Pages無法編譯問題及解決編譯
- Windows解決斷後佔用問題Windows
- 快取世界中的三大問題及解決方案快取
- 記一次 rr 和硬體斷點解決記憶體踩踏問題斷點記憶體
- Solaris Linux SSH緩慢診斷與解決Linux
- 一次 nginx 返回 302 問題解決Nginx
- 【ORA-4030/4031】自動記憶體管理AMM中的ORA-4030/4031問題記憶體
- SQL Server database mail問題診斷一例SQLServerDatabaseAI
- 快取過程存在的三大問題及解決方案快取
- 一次ORACLE IO效能診斷案例Oracle
- 一次Oracle診斷案例-Spfile案例Oracle
- 一次SGA與Swap故障診斷
- Harbor搭建及配置 問題解決
- Git常見問題及解決Git
- 跨域問題及解決方案跨域
- redis安裝及問題解決Redis
- Nature Medicine論文展示DeepMind眼疾診斷里程碑:臨床專家級、「解決」黑箱問題
- 壓力測試事務率不高問題診斷
- 解決ELK日誌被截斷的問題
- 一次DG故障診斷過程分析
- 一次Oracle診斷案例-SGA與SwapOracle
- WordPress:常見問題及解決方案
- django安裝xadmin及問題解決Django
- Nacos 常見問題及解決方法
- UltraEdit常見問題及解決教程
- IPython的安裝及問題解決Python
- 測試靈魂三問及解決方案
- 記錄一次解決App崩潰問題的解決方案APP