環境介紹
操作系統: AIX 7.1
數據庫:Oracle 11.2.0.4
一般情況下,收到Undo表空間報警基本都是忽略的,因為大部分統計Undo使用率的SQL都是把UNEXPIRED部分算作已使用部分的,實際上其中有較大部分是可以重用的。
這兩天持續報Undo表空間剩余可用空間低於1%,所以查看了一下原因。
查詢SQL語句:
SQL> select tablespace_name, status, sum(bytes/1024/1024) "MB"
from dba_undo_extents
group by tablespace_name, status
order by 1, 2;
不同狀態的含義:
ACTIVE
:有活動事務在使用 Undo,這部分空間屬於Session正在使用的空間;
UNEXPIRED
:事務提交並且沒到undo_retention設置時間之前,這些Undo Block還沒有過期,但是已經沒有活動事務在使用了,在超過undo_retention設置時間之后,這部分空間會變成EXPIRED狀態;
EXPIRED
:事務提交並且到undo_retention設置時間之后,這些Undo Block已經過期了,這部分空間是可以重用的,屬於未使用空間;
可以看到 ACTIVE和UNEXPIRED的大小達到98272 MB(UNDOTBS1表空間大小98296 MB),使用率接近100%。
查找資料發現Oracle 10g中引入了一個新的自動調整undo_retention的特性,在Oracle Database 10g中當自動undo管理被默認啟用,每隔10分鍾會自動設置當前的undo_retention,Oracle Database嘗試至少保留舊的undo信息到該時間。該信息可以在視圖v$undostat查到。
SQL> select begin_time,tuned_undoretention from V$UNDOSTAT where rownum < 11;
BEGIN_TIME TUNED_UNDORETENTION
------------------------------ -------------------
2021/09/23 09:53:51 653881
2021/09/23 09:43:51 654763
2021/09/23 09:33:51 654644
2021/09/23 09:23:51 654513
2021/09/23 09:13:51 654883
2021/09/23 09:03:51 654863
2021/09/23 08:53:51 651826
2021/09/23 08:43:51 655097
2021/09/23 08:33:51 655045
2021/09/23 08:23:51 654809
2021/09/23 08:13:51 654226
可以看到Oracle設置的undo_retention時間高達65W多,所以導致出現大量的UNEXPIRED占用。
Metalink里有一篇文章介紹Automatic Tuning of Undo Retention引起空間問題的文章:
Automatic Tuning of Undo_retention Causes Space Problems [ID 420525.1]
文章里給出了3個解決方法:
1)設置Undo數據文件為可擴展並且MAXSIZE為數據文件當前大小;
SQL> alter database datafile ‘<datafile_flename>’ autoextend on maxsize <current_size>;
感覺這個設置就是為了讓Automatic Tuning of Undo Retention能更准確的估算v$undostat.tuned_undoretention的大小,但是發現好像不是太管用,至少沒有立竿見影。
2)設置隱藏參數_smu_debug_mode
SQL> alter system set "_smu_debug_mode" = 33554432;
設置這個之后v$undostat.tuned_undoretention會取(maxquerylen secs + 300)和參數undo_retention里的最大值。網上有人設置之后出現大量ORA-01555錯誤,遂放棄這個方法。
3)設置隱藏參數_undo_autotune
SQL> alter system set "_undo_autotune" = false;
這個方法就比較暴力了,直接禁用了Automatic Tuning of Undo Retention特性。
4)非官方解決方法(后來再查發現也是官方建議,參考Note 742035.1)
alter system set "_highthreshold_undoretention"=86400;
在查undo相關參數的時候,發現如下參數,感覺應該有第4種解決方法:
KSPPINM KSPPSTVL KSPPDESC
---------------------------------------- -------------------- ------------------------------------------------------------
_highthreshold_undoretention 4294967294 high threshold undo_retention in seconds
測試之后,發現該參數的值可以限定v$undostat.tuned_undoretention的最大大小。
SQL> select begin_time,maxquerylen,expiredblks,unexpiredblks,activeblks,tuned_undoretention from V$UNDOSTAT where rownum < 11;
tuned_undoretention最大值限定之后,UNEXPIRED部分就開始釋放了,所以方法這個還是有效的。並且將該值限定到86400,也就是一天,應該沒有什么事務需要占用一天的Undo了,有也需要提出來優化。
SQL> select tablespace_name, status, sum(bytes/1024/1024) "MB"
from dba_undo_extents
group by tablespace_name, status
order by 1, 2;
至此,該問題解決,既使用了Automatic Tuning of Undo Retention的新特性,也不會導致Undo表空間使用率的問題。完美!
附錄
Maclean博客里查詢Undo使用率的SQL
查詢undo真實的使用率:
prompt
prompt ############## IN USE Undo Data ##############
prompt
select
((select (nvl(sum(bytes),0)) from dba_undo_extents where tablespace_name in (select tablespace_name from dba_tablespaces where retention like '%GUARANTEE' ) and status in ('ACTIVE','UNEXPIRED')) *100) / (select sum(bytes) from dba_data_files where tablespace_name in (select tablespace_name from dba_tablespaces where retention like '%GUARANTEE' )) "PCT_INUSE" from dual;
此外,從Maclean的博客中找到兩條實用的UNDO表空間監控的查詢SQL:
--在Oracle 10g版本中可以使用V$UNDOSTAT視圖用於監控實例中當前事務使用UNDO表空間的情況。視圖中的每行列出了每隔十分鍾從實例中收集到的統計信息。
--每行都表示了在過去7*24小時里每隔十分鍾UNDO表空間的使用情況,事務量和查詢長度等信息的統計快照。 --UNDO表空間的使用情況會因事務量變化而變化,一般我們在計算時同時參考UNDO表空間的平均使用情況和峰值使用情況 --以下SQL語句用於計算過去7*24小時中UNDO表空間的平均使用量 select ur undo_retention, dbs db_block_size, ((ur * (ups * dbs)) + (dbs * 24)) / 1024 / 1024 as "M_bytes" from (select value as ur from v$parameter where name = 'undo_retention'), (select (sum(undoblks) / sum(((end_time - begin_time) * 86400))) ups from v$undostat), (select value as dbs from v$parameter where name = 'db_block_size'); --以下SQL語句則按峰值情況計算UNDO表空間所需空間: select ur undo_retention, dbs db_block_size, ((ur * (ups * dbs)) + (dbs * 24)) / 1024 / 1024 as "M_bytes" from (select value as ur from v$parameter where name = 'undo_retention'), (select (undoblks / ((end_time - begin_time) * 86400)) ups from v$undostat where undoblks in (select max(undoblks) from v$undostat)), (select value as dbs from v$parameter where name = 'db_block_size');
Automatic Tuning of Undo Retention特性介紹
Oracle 10g中引入了一個新的自動調整undo_retention的特性,其目的是為了減少ORA-01555錯誤出現的概率,Oracle會忽略UNDO_RETENTION參數設置的閥值,而是根據UNDO表空間的大小和使用率來自動調整UNDO信息的保留時間。會造成的影響是UNDO表空間的區(extent)中大部分都是未過期狀態(unexpired),這就會導致數據庫在給事務分配UNDO塊時,會優先使用UNDO表空間的的空閑空間分配,而不是覆蓋已經分配的空間,這使得UNDO表空間的使用率保持在一個較高的水平。
Oracle數據庫在為事務進行分配UNDO塊時,會按照這樣的算法和流程:
1. 如果當前區(extent)中還有空閑塊,在需要空間時會繼續使用本區(extent)中的空閑塊。
2. 在當前區(extent)使用完后,如果下一個區(extent)是過期狀態(expired),那么就跳轉到下一個區(extent)的第一個數據塊。
3. 如果下一個區(extent)不是過期狀態(expired),就從UNDO表空間申請空間,如果UNDO表空間中存在空閑的空間,就分配新的區(extent)加入到undo segment,然后跳轉到新區(extent)的第一個數據塊。
4. 如果沒有剩余空閑的區(extent),則會從OFFLINE狀態的回滾段中竊取(STEAL)過期的區,加入當前的回滾段,並使用第一個數據塊。
5. 如果OFFLINE狀態的回滾段中沒有過期的區,那么會從ONLINE狀態的回滾段竊取(STEAL)過期的區加入當前的回滾段,並使用第一個數據塊。
6. 如果UNDO表空間能夠自動擴展,則會擴展UNDO表空間,並將新區加入到當前回滾段中。
7. 如果undo表空間數據文件不能擴展,調低10%的retention值,然后竊取(STEAL)在短保留時間的過期區,如果還未找到過期區,則繼續以10%的速度減少回滾的保留時間。
8. 隨機從其他OFFLINE狀態的回滾段中竊取(STEAL)未過期的(unexpired)的區。
如果以上的嘗試都失敗,那么久會報ORA-30036錯誤。
從上面的步驟可以看出,事務會優先使用UNDO空閑空間、過期狀態(expired)的UNDO區,然后會嘗試擴展表空間的數據文件,只有在以上步驟都得不到獲得UNDO表空間后,才會去使用未過期(unexpired)的UNDO區。
引用鏈接:https://blog.csdn.net/w892824196/article/details/100123813