oracle學習筆記 如何解決ORA-04031錯誤

oracle學習筆記

如何解決ORA-04031錯誤

一)查找執行次數爲一的語句
select SQL_FULLTEXT from v$sql where EXECUTIONS=1 order by sql_text;
此語句出來的結果按sql_text排序
如果某些sql沒有共享的話
在某一個區域你會發現有一堆的sql語句
它執行一次而且它的靜態部分是相同的動態部分不相同
這時就能知道沒有共享

可以這麼做
SQL> spool 1.lst
然後執行
SQL> select SQL_FULLTEXT from v$sql where EXECUTIONS=1 order by sql_text;
然後
SQL> spool off

1)spool命令
SPOOL是SQLPLUS的命令,不是SQL語法裏面的內容
在sqlplus中用來保存或打印查詢結果

spool 1.lst
表示將此後的命令及命令的輸出結果保存到用戶目錄下的1.lst文件中
spool off
結束內容的輸出
舉個小例子:
SQL> spool example.lst
SQL> set linesize 100
SQL> spool off
SQL> exit
Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options
[oracle@redhat4 ~]$ vi example.lst
下面兩行是spool保存到example.lst文件的內容
SQL> set linesize 100
SQL> spool off

2)v$sql視圖
看一下查詢用到的視圖v$sql的結構
SQL> DESC v$sql;
可以發現
 SQL_TEXT                                                                                                                                    VARCHAR2(1000)
 SQL_FULLTEXT                                                                                                                                CLOB
 SQL_ID                                                                                                                                      VARCHAR2(13)

語句中使用的視圖v$sql中有很多字段,目前只看這三個字段

LOB (large object) datatypes(大數據類型)
oracle中有四種大數據類型blob,clob,bfile,nclob

SQL_FULLTEXT的數據類型爲CLOB
CLOB: Character Large Object(字符型大數據類型)
即字符型lob,可容納單字節的字符,最長可以達到4GB,存貯在數據庫中

oracle中有多種方法來檢索或操作lob數據,通常的處理方法是通過dbms_lob包

SQL_FULLTEXT字段可以把sql語句所有內容保存起來
是爲了防止一些超大的sql語句使用一般數據類型保存時不夠長度的情況。
但使用select語句直接查詢此字段時只顯示了最前面的一部分字符(80個字符),
顯示時內容被截斷了,但實際內容沒有被截斷。
簡單查詢時使用SQL_TEXT字段1000個字符的顯示,反而顯示的內容多一些。

3)看結果
[oracle@redhat4 ~]$ ls
1.lst  Desktop
[oracle@redhat4 ~]$ vi 1.lst
查看命令及結果被存到了1.lst文件中

可以把這個文件放到windows系統裏面
放到excel裏面排一下序,更好看一些。

如何從系統裏面找一些哪些sql語句沒有共享
查詢執行次數爲一的語句是一個小技巧是很好的一個方法

二)命中率
就是librarycache命中率和rowcache命中率

命中率反應的是軟解析成功的次數
嚴格要求99%以上
甚至接近100%
如果是98%就說明命中率比較差了。

應該在數據庫跑了一段時間以後去判斷命中率
庫剛起來就看命中率,那時剛剛執行,命中率肯定低
跑了一段時間以後命中率肯定是很高的。

軟解析的命中率
SQL> select sum(pinhits)/sum(pins)*100 from v$librarycache;

SUM(PINHITS)/SUM(PINS)*100
--------------------------
                90.5713553

本人的演示的數據庫沒有什麼負載而且跑得比較少
所以命中率比較低。

rowcache的命中率
SQL> select sum(gets),sum(getmisses),100*sum(gets-getmisses)/sum(gets)  from v$rowcache where gets>0;

 SUM(GETS) SUM(GETMISSES) 100*SUM(GETS-GETMISSES)/SUM(GETS)
---------- -------------- ---------------------------------
   1234298         130366                        89.4380449

一般rowcache的命中率很高的
因爲實驗環境沒有運行多少時間,不能真實反應實際情況

rowcache一般都非常高,很少出問題
容易出問題的是librarycache

三)如何解決oracle的4031錯誤

簡單的講一下如何解決oracle的4031錯誤

1)alter system flush shared_pool;
臨時性的解決辦法,執行上面語句
這時sharedpool的librarycache裏面所有的chunk會釋放
會有大量的大大小小的chunk回到free裏面去
這時4031錯誤暫時會緩解
但這只是治標不治本的一個辦法

2)共享SQL
最好還是要判斷一下哪些語句沒有共享sql
然後把這個問題告訴開發人員
讓開發人員去解決這個問題,讓他共享sql

共享sql如果開發人員做不到的話
我們可以改一個參數cursor_sharing

sql語句沒有共享有很多種原因
第一種原因是因爲裏面有字面值
沒有使用綁定變量
第二種我們的sql語句裏面加了空格、大小寫、回車
造成書寫不規範

對於第一種情況如果是字面值沒有使用綁定變量
把cursor_sharing改成force以後主動可以解決這個問題
就是你如果使用字面值oracle會強行綁定變量
對於第二種改cursor_sharing對書寫不規範這個問題是沒法解決的
儘量的讓開發人員去改,改不了的話
我們把cursor_sharing 改成force

3)把執行計劃keep起來
oracle數據庫中有一個包dbms_shared_pool
它可以實現keep功能

大量的硬解析出現,產生很多很小的free trunk
接着出現一個比較大的sql
這時候在sharedpool裏面的free裏面就找不到合適的truck使用
於是出現了4031錯誤。

也有可能數據庫正常運行
free少了是sharedpool分的比較小
某個大sql產生4031不是因爲硬解析過多造成的
而確實是這個sql太大了
這時可以使用dbms_shared_pool包裏面的存儲過程
將這個sql語句強行緩存到sql裏面去
然後它永遠不會被置換出來
它不會因爲sharedpool空間不夠了被擠出來
這時也可以避免一個大的sql語句
在後面執行時出現問題

舉例講
數據庫裏面容易出現這種情況
當oracle在free裏面找不到大truck的時候
它會想辦法到librarycache裏面找大truck
找到以後把它釋放了,把空間要回來
如數據庫裏面librarycache裏面有一個很大的truck長時間沒有執行
它被置換出去了到free裏面去了
被分爲兩半使用了
如果後面在執行這個大truck的時候可能就沒有空間了
這時候就容易出現4031錯誤
爲了解決這個問題
可以將最大的前幾個truck(我們可以排序)
強行keep起來
避免4031錯誤出現

要使用dbms_shared_pool包首先要創建它
方法是執行ORACLE_HOME目錄下的/rdbms/admin/dbmspool.sql文件
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> @?/rdbms/admin/dbmspool.sql

Package created.

Grant succeeded.

View created.

Package body created.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
包創建完成
此包的創建只能以管理員身份運行才能正常完成。

然後使用
select * from v$db_object_cache where sharable_mem > 10000
and (type = 'PACKAGE' or type='PACKAGE BODY' or type = 'FUNCTION' or type='PROCEDURE')
and kept = 'NO';
查一下sql裏面有哪些比較大的
sharable_mem > 10000
佔用sharedmemeory內存大於10K的哪些對象
然後把對象的擁有者和名字找出來
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> select * from v$db_object_cache where sharable_mem > 10000
                and (type = 'PACKAGE' or type='PACKAGE BODY' or type = 'FUNCTION' or type='PROCEDURE')
                and kept = 'NO';  2    3

OWNER
----------------------------------------------------------------
NAME
----------------------------------------------------------------------------------------------------
DB_LINK                                                          NAMESPACE
---------------------------------------------------------------- ----------------------------
TYPE                         SHARABLE_MEM      LOADS EXECUTIONS      LOCKS       PINS KEP
---------------------------- ------------ ---------- ---------- ---------- ---------- ---
CHILD_LATCH INVALIDATIONS
----------- -------------
SYSMAN
EMD_COLLECTION
                                                                 BODY
PACKAGE BODY                        33217          1          5          0          0 NO
          3             0

SYS
DBMS_APPLICATION_INFO
                                                                 TABLE/PROCEDURE
PACKAGE                             16745          2          0          4          0 NO
          3             0

SYSMAN
EM_PING
                                                                 TABLE/PROCEDURE
PACKAGE                             37238          2          0          2          0 NO
          2             0

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
結果較多就不全列了

如其中的一行
SYS
DBMS_APPLICATION_INFO
                                                                 TABLE/PROCEDURE
PACKAGE                             16745          2          0          4          0 NO
          3             0
包名DBMS_APPLICATION_INFO
擁有者SYS
KEP狀態爲NO,即沒有被keep

把它keep到內存裏面去
需要使用dbms_shared_pool.keep('對象名');

包的執行可以使用如下形式
SQL> execute dbms_shared_pool.keep('DBMS_APPLICATION_INFO');

SQL> begin
dbms_shared_pool.keep('DBMS_APPLICATION_INFO');
commit;
end;

執行一下
SQL> execute dbms_shared_pool.keep('DBMS_APPLICATION_INFO');

PL/SQL procedure successfully completed.

查詢一下一keep的對象
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> select * from v$db_object_cache where sharable_mem > 10000
                and (type = 'PACKAGE' or type='PACKAGE BODY' or type = 'FUNCTION' or type='PROCEDURE')
                and kept = 'YES';  2    3

OWNER
----------------------------------------------------------------
NAME
----------------------------------------------------------------------------------------------------
DB_LINK                                                          NAMESPACE
---------------------------------------------------------------- ----------------------------
TYPE                         SHARABLE_MEM      LOADS EXECUTIONS      LOCKS       PINS KEP
---------------------------- ------------ ---------- ---------- ---------- ---------- ---
CHILD_LATCH INVALIDATIONS
----------- -------------
SYS
DBMS_APPLICATION_INFO
                                                                 TABLE/PROCEDURE
PACKAGE                             16745          2          0          6          0 YES
          3             0
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
我的結果只有一條就是上面keep的DBMS_APPLICATION_INFO對象
因爲以前沒有做過keep工作

在dbms_shared_pool包執行時默認操作的對象的所有者是SYS
屬於其它所有者的對象默認操作會報錯
如這個對象
SYSMAN
EMD_COLLECTION
                                                                 BODY
PACKAGE BODY                        33217          1          5          0          0 NO
          3             0
擁有者SYSMAN
對象名EMD_COLLECTION
如這樣執行
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> execute dbms_shared_pool.keep('EMD_COLLECTION');
BEGIN dbms_shared_pool.keep('EMD_COLLECTION'); END;

*
ERROR at line 1:
ORA-06564: object EMD_COLLECTION does not exist
ORA-06512: at "SYS.DBMS_UTILITY", line 114
ORA-06512: at "SYS.DBMS_SHARED_POOL", line 45
ORA-06512: at "SYS.DBMS_SHARED_POOL", line 53
ORA-06512: at line 1
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
結果報錯
解決辦法要在對象名前面標示擁有者
SQL> execute dbms_shared_pool.keep('SYSMAN.EMD_COLLECTION');

PL/SQL procedure successfully completed.
執行成功

解除某個對象的keep狀態可以使用dbms_shared_pool包提供的unkeep方法
SQL> execute dbms_shared_pool.unkeep('DBMS_APPLICATION_INFO');

PL/SQL procedure successfully completed.

SQL> execute dbms_shared_pool.unkeep('SYSMAN.EMD_COLLECTION');

PL/SQL procedure successfully completed.

執行清理shared_pool內存
alter system flush shared_pool;
命令後keep狀態的對象仍然保持keep狀態
而在oralce數據庫重啓後不再有處於keep狀態的對象

4)如何增加sharedpool
使用命令
alter system set shared_pool_size=150M scope=both;
150M就是要設置的值

1、sga_target和sga_max_size的設置及關係

oracle以前的版本10以前
數據庫裏面重點有6個大的池子
在oracle老的版本里面每個池子需要給它供應大小
sharedpool,buffer cache,redolog buffer,stream,large,javapool
都要固定的大小,一旦固定大小它就不能變
當然我們可以改

但是有可能這種情況
sharedpool設了兩個G大小但實際用了一個G
但是buffercache設了九個G它可能需要9.5個G
oralce裏面有空閒空間,
但2G給了sharedpool,還浪費着呢,可buffercache還不夠

所以oracle10開始做這麼一件事情
oracle對SGA來講
它統一設一個參數SGA target
比如設sga_target等於12個G
這個時候oracle的
sga_target裏面包括sharedpool和buffercache那六個池子
把參數統一設了12個G以後
oracle對各個內存塊六個池子oracle根據需求動態的去分配
我們從理論上看上去應該很好啊
不浪費空間
所以說oracle新的版本里面我們只設一個參數sga_target
這是個動態參數
在數據庫運行期間我們可以動態去設置
SGA裏面的六個池子空間可以動態分配
即保證了空間又沒有浪費了空間

還有個參數sga_max_size
是個靜態參數
一般的情況下
sga_target等於sga_max_size
但sga_max_size改完以後數據庫需要重啓
sga_max_size是用來約束sga_target的

舉一個假設的例子:
數據庫使用物理內存比如64G
我們給了oracle數據庫50%,也就是給了SGA_target 32G
我們想這麼做,也給了
max參數32G
target參數也是32G
這時假設沒有max這個東西
target是32G
我們知道sga_target可以動態改
想把它改成36個G
結果多寫了一個0,把它改成360個G了
這有可能,因爲是動態參數
出現一個問題內存一共才64G
這時oracle要360個G
一下就會把內存所有都給了oracle
而且swap空間也給了oracle
這時系統會瞬間因爲內存耗盡,操作系統掛起
操作系統掛起了oracle也就掛起了
會死機、導致數據文件損壞
所以sga_target可以動態設
但是一旦設錯了數據庫可能會引起死機
出現問題

所以需要另外設一個參數
oracle提供了一個參數max參數
平時
物理內存64G
可以把max參數設爲48G
因爲規定oracle target參數再怎麼設置高
target只能在max的48個G以下設置
設40G或42G都沒問題但不要超過max

max它是靜態參數要改必須重啓數據庫
存在的目的就是爲了約束設sga_target時的隨意性
max設了個sga_target可用的最大值 

現在看一下當前這兩個參數的值
SQL> show parameter sga

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
lock_sga                             boolean     FALSE
pre_page_sga                         boolean     FALSE
sga_max_size                         big integer 272M
sga_target                           big integer 272M
目前sga_target和sga_max_size大小爲272M

2、shared_pool大小的設置

先看一下目前大小
SQL> show parameter shared_pool;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_reserved_size            big integer 8M
shared_pool_size                     big integer 0

shared_pool_size的默認值oracle設的是0M
就是未指定由oracle自動分配大小

給它分配個值
SQL> alter system set shared_pool_size=20;

System altered.

再看大小
SQL> show parameter shared_pool;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_reserved_size            big integer 8M
shared_pool_size                     big integer 4M

這裏設置時shared_pool_size=20,20後面沒有帶參數,20被理解爲20個字節
因爲此參數設置時以4M爲基本單位,
最終的值都是4M的整數倍,所以系統給了它一個值4M。

再去查一個參數
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> select COMPONENT,CURRENT_SIZE from V$SGA_DYNAMIC_COMPONENTS;

COMPONENT                                                        CURRENT_SIZE
---------------------------------------------------------------- ------------
shared pool                                                          88080384
large pool                                                            4194304
java pool                                                             4194304
streams pool                                                                0
DEFAULT buffer cache                                                180355072
KEEP buffer cache                                                           0
RECYCLE buffer cache                                                        0
DEFAULT 2K buffer cache                                                     0
DEFAULT 4K buffer cache                                                     0
DEFAULT 8K buffer cache                                                     0
DEFAULT 16K buffer cache                                                    0
DEFAULT 32K buffer cache                                                    0
ASM Buffer Cache                                                            0

13 rows selected.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
實際sharedpool的大小不是4M是88M
參數值改成了4M實際大小88M
並沒有變化

我們可以設sga_target 1G或500M
目前我使用的是272M
然後orale根據
sga_target設置大小、shared_pool_size設置大小、系統的負載
自動的把sharedpool設爲88M
我們也可以手工的把sharedpool設一下
如果小於當前值88M,oracle不予理會還是88M

如果這時shared_pool_size設爲180M
oracle就會用180M
原理
新設置的參數大小必須大於先前sga_target總的自動給它分配的空間大小
纔會使shared pool實際的空間大小發生改變
所以show parameter看的並不準
需要查詢

這就是講的增加sharedpool空間
新設置的參數必須大於sga_target目前總的自動給它分配的空間
才能在設置新的大小值後立即使實際值增加

例子:
SQL> alter system set shared_pool_size=100M;

System altered.

參數設置值
SQL> show parameter shared_pool;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_reserved_size            big integer 8M
shared_pool_size                     big integer 100M

實際大小
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
SQL> select COMPONENT,CURRENT_SIZE from V$SGA_DYNAMIC_COMPONENTS;

COMPONENT                                                        CURRENT_SIZE
---------------------------------------------------------------- ------------
shared pool                                                         104857600
large pool                                                            4194304
java pool                                                             4194304
streams pool                                                                0
DEFAULT buffer cache                                                163577856
KEEP buffer cache                                                           0
RECYCLE buffer cache                                                        0
DEFAULT 2K buffer cache                                                     0
DEFAULT 4K buffer cache                                                     0
DEFAULT 8K buffer cache                                                     0
DEFAULT 16K buffer cache                                                    0
DEFAULT 32K buffer cache                                                    0
ASM Buffer Cache                                                            0

13 rows selected.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
這時候shared pool的實際空間發生了變化,
增大了,值爲104M左右。

即使
alter system flush shared_pool;
此值也是sga自動分配給它的值,並且自動分配給它的值肯定大於自己設置的值。

5)保留區

我們知道shared_pool裏面有free、librarycache、rowcache

隨着硬解析的增加
free裏面的chunk很多變小將來可能出現4031錯誤
我們也知道不管硬解析多少,隨着時間的增長
free裏面都有可能出現空間不夠的情況因爲大量的小的chunk
都有可能會出現數據庫跑了一段時間以後出現一個大的sql

有時候4031錯誤看上去不能避免

oracle爲了解決這個問題做了另一個事情

shared_pool裏面單獨的劃出一塊空間來,
保留區 
叫shared_pool_reserved
這個空間,就是隻是用來緩存大對象
當一個對象的尺寸超過一定的閾值的時候
它就不會到free裏面去找空間
而是到保留區裏面找空間
如果我們把保留區設的足夠大的話
可以減少很多4031錯誤的產生

我們看一個查詢
select REQUEST_MISSES from v$shared_pool_reserved;
就是用來查在保留區裏請求空間失敗的次數
只要是有一次就肯定會發生4031錯誤
因爲既然到保留區裏面找空間
說明是大對象
在保留區都找不到的話,它就會直接報錯,報4031錯誤
所以這個數值最好是零

SQL> select REQUEST_MISSES from v$shared_pool_reserved;

REQUEST_MISSES
--------------
             0
值爲0說明從來沒有發生因爲在保留區找不到空間而產生4031錯誤的情況。

所以保留區我們要設的大一些。
如果查詢值大於0,我們要調整參數shared_pool_reserved_size

SQL> show parameter shared;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
hi_shared_memory_address             integer     0
max_shared_servers                   integer
shared_memory_address                integer     0
shared_pool_reserved_size            big integer 8M
shared_pool_size                     big integer 4M
shared_server_sessions               integer
shared_servers                       integer     1

其中
shared_pool_reserved_size            big integer 8M

8M即爲值大小

如果REQUEST_MISSES大於0的話
或者數值比較大的話
我們要將reserved調大一些

shared_pool_reserved_size是一個靜態參數所以修改要使用

SQL> alter system set shared_pool_reserved_size=10M scope=spfile;

System altered.

值修改後重啓oracle才能生效。

系統重啓然後查詢參數值:
SQL> show parameter shared_pool;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
shared_pool_reserved_size            big integer 10M
shared_pool_size                     big integer 4M

設置保留區這也是4031錯誤的一個解決辦法

四)解決oracle的4031錯誤方法總結
        1、alter system flush shared_pool;
2、共享SQL
3、select * from v$db_object_cache where sharable_mem > 10000
and (type = 'PACKAGE' or type='PACKAGE BODY' or type = 'FUNCTION' or type='PROCEDURE')
and kept = 'NO';
執行dbms_shared_pool.keep('對象名');
DBMS_SHARED_POOL
@?/rdbms/admin/dbmspool.sql
4、保留區
select REQUEST_MISSES from v$shared_pool_reserved;
5、增加shared pool空間
select COMPONENT,CURRENT_SIZE from V$SGA_DYNAMIC_COMPONENTS;
show parameter sga_target
show parameter sga_max_size
alter system set shared_pool_size=150M scope=both;
上面的方法摘自老師的教案
簡單回顧一下
1、flush一下 治標不治本
2、共享sql 最好使用綁定變量 
   綁定變量實現不了的話 
   可以改cursor_sharing只能解決一種辦法,就是字面值沒有使用綁定變量的問題。
3、我們可以對一些大的對象進行keep
4、單獨的劃出一塊保留區
5、增加shared_pool的大小

解決4031錯誤基本就這五種辦法

2016年8月27日
文字:韻箏
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章