關于Ora-01555這個問題,網上已經有很多讨論了,感興趣的同學自己搜尋下。
那麼對于此問題的解決無外乎以下兩種
1 減少查詢時間
2 增加undo_tablsespace 大小
減少查詢時間,優化的事情,本文不做讨論
本文想要讨論的是undo_tablsespace 設定多大合适。
Oracle提供了一個非常不錯的視圖 v$undostsat
v$undostat 根據官方文檔 http://docs.oracle.com/cd/E11882_01/server.112/e40402/dynviews_3118.htm#REFRN30295 Each row in the view keeps statistics collected in the instance for a 10-minute interval.The view contains a total of 576 rows, spanning a 4 day cycle.
每十分鐘生成一行,保留576行 即四天的資料
Column | Datatype | Description |
BEGIN_TIME | DATE | 定義時間段起始 |
END_TIME | DATE | 定義時間段結束 |
UNDOTSN | NUMBER | 時間段内最後活動的undo tablespace的編号 |
UNDOBLKS | NUMBER | undo block 消耗總數 |
TXNCOUNT | NUMBER | 時段内發生多少個事務 |
MAXQUERYLEN | NUMBER | 時段内運作的sql最長執行時間,此參數可以用來衡量undo_retention設定是否合理 |
MAXQUERYID | VARCHAR2(13) | 運作時間最長的SQL ID |
MAXCONCURRENCY | NUMBER | 時段内最大事務并發數 |
UNXPSTEALCNT | NUMBER | 試圖從其他unexpired extents 偷取undo space的次數 |
UNXPBLKRELCNT | NUMBER | 為被其他事務使用 某一undo segment 删除的unexpired blocks數量 |
UNXPBLKREUCNT | NUMBER | 事務重用unexpired undo blocks的數量 |
EXPSTEALCNT | NUMBER | 從其他復原段偷取expired undo blocks 的數量 |
EXPBLKRELCNT | NUMBER | 從從其他復原段中偷取expired undo blocks 的數量 |
EXPBLKREUCNT | NUMBER | 被同一復原段重用的expired undo blocks的數量 |
SSOLDERRCNT | NUMBER | 時間段内ora-01555發生的次數 |
NOSPACEERRCNT | NUMBER | 時段内undo tablespace 用盡,無法擷取資料的次數 |
ACTIVEBLKS | NUMBER | 本執行個體時段内active extent undo block的總數 |
UNEXPIREDBLKS | NUMBER | 本執行個體時段内 unexpired extent undo block的總數 |
EXPIREDBLKS | NUMBER | 本執行個體時段内 expired extent undo block的總數 |
TUNED_UNDORETENTION | NUMBER | AUM 自動調整UNDO_RETENTION的參數值,用以确定送出後的undo block是否能清理 |
根據以上視圖很容易算出undo tablespace size
metalink 給出的公式是
UR =undo_retention參數值 UPS= 每秒産生的undo block數量 DBS = undo tablespace block size
10g之前
SELECT (UR * (UPS * DBS)) AS "Bytes"
FROM (SELECT value AS UR FROM v$parameter WHERE name = 'undo_retention'),
(SELECT undoblks / ((end_time - begin_time) * 86400) AS UPS
FROM v$undostat
WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat)),
(SELECT block_size AS DBS
FROM dba_tablespaces
WHERE tablespace_name =
(SELECT UPPER(value)
FROM v$parameter
WHERE name = 'undo_tablespace'));
10g 以後
SELECT (UR * (UPS * DBS)) AS "Bytes"
FROM (select max(tuned_undoretention) AS UR from v$undostat),
(SELECT undoblks / ((end_time - begin_time) * 86400) AS UPS
FROM v$undostat
WHERE undoblks = (SELECT MAX(undoblks) FROM v$undostat)),
(SELECT block_size AS DBS
FROM dba_tablespaces
WHERE tablespace_name =
(SELECT UPPER(value)
FROM v$parameter
WHERE name = 'undo_tablespace'));
當然也可以用過DBMS_ADVISOR來擷取Oracle關于undo的建議設定,當然不是每次都能擷取到建議,相比還是上面提供的腳本比較友善。
下面語句來自于官方文檔 我稍微做了一點修改 其中123 124是snapshot的ID 需要根據實際做修改。
SET SERVEROUTPUT ON
DECLARE
tid NUMBER;
tname VARCHAR2( 30);
oid NUMBER;
BEGIN
DBMS_ADVISOR.CREATE_TASK('Undo Advisor' , tid, tname, 'Undo Advisor Task' );
DBMS_ADVISOR.CREATE_OBJECT(tname, 'UNDO_TBS' , null, null, null, 'null', oid);
DBMS_ADVISOR.SET_TASK_PARAMETER(tname, 'TARGET_OBJECTS' , oid);
DBMS_ADVISOR.SET_TASK_PARAMETER(tname, 'START_SNAPSHOT' , 123);
DBMS_ADVISOR.SET_TASK_PARAMETER(tname, 'END_SNAPSHOT' , 124);
DBMS_ADVISOR.SET_TASK_PARAMETER(tname, 'INSTANCE' , 1);
DBMS_ADVISOR.execute_task(tname);
DBMS_OUTPUT.put_line( 'select * from dba_advisor_log WHERE TASK_ID ='||tid || ' ;');
DBMS_OUTPUT.put_line( 'select * from DBA_ADVISOR_FINDINGS WHERE TASK_ID ='||tid|| ' ;');
DBMS_OUTPUT.put_line( 'select * from DBA_ADVISOR_RECOMMENDATIONS WHERE TASK_ID ='||tid||' ;');
END;
/