今回はUNDO表領域の拡張エラー(ORA-30036)について検証しました。
ORA-30036はUNDO表領域に使用可能な領域がなくなり、新たにエクステントを確保(=UNDOセグメント拡張)できない場合に発生します。
Oracleはデータ変更(更新、削除など)時に変更前のデータ(UNDOデータ)を生成し、UNDOセグメントに書き込んで一定期間保持します(UNDOデータは主にトランザクションのロールバックや読取り一貫性で使用します)
たとえば、DELETE文実行時に生成したUNDOデータをUNDOセグメントに書き込んでいる途中でUNDOセグメントがいっぱいになり、
新たにエクステントを確保しようとしたがUNDO表領域に使用可能な領域がないためUNDOセグメント拡張に失敗するというケースもあります。
1. Oracle側での対応案
1-1. UNDO表領域のサイズを拡張する
UNDO表領域のサイズを手動拡張する。ユーザが安全と見積もったサイズで拡張するためORA-30036の発生確率は低くなる
1-2. UNDO表領域の自動拡張をONにする
UNDOセグメント不足時、事前に定義した最大サイズまでUNDO表領域を一定サイズごとに自動拡張する。必要に応じて自動拡張するためORA-30036の発生確率は低くなる
1-3. UNDO保存の保証を無効にする
UNDO保存の保証とは、最小UNDO保存期間内のUNDOデータは上書きされないことを保証する機能。有効の場合、最小UNDO保存期間内のUNDOデータは上書されず、他の領域に書き込まれるためORA-30036の発生確率が高くなる
無効の場合、UNDOセグメント不足時は最小UNDO保存期間内のUNDOデータであっても上書きされるためORA-30036の発生確率は低くなる
1-4. 最小UNDO保存期間の値を小さくする
UNDO保存の保証が有効の場合、最小UNDO保存期間内のUNDOデータは上書きされないためエクステントの使用効率が悪くなる。
最小UNDO保存期間の値を小さくする(UNDOデータが上書きされない期間を短くする)ことでエクステントの使用効率が向上するためORA-30036の発生確率は低くなる
※自動拡張OFF、かつ、UNDO保存の保証が無効の場合、最小UNDO保存期間の値は無視される(UNDO保存期間はOracleで自動チューニングされる)
2 ユーザ側での対応案
2-1. データ処理件数を制御
データの処理件数を絞ってデータ変更する。1回のトランザクションで生成するUNDOデータが減るためORA-30036の発生確率は低くなる
2-2. TRUNCATE文を使用する
DELETE文ではなくTRUNCATE文でデータを削除(切り捨て)する。TRUNCATE文はUNDOデータを生成しないためORA-30036は発生しない
検証環境
OS:Oracle Linux 6.5
DB:Oracle Database 12c Release 1 (12.1.0.2.0) Enterprise Edition
前提
・自動UNDO管理
・UNDO保存の保証:無効
・UNDO保存期間:900秒 ※今回は自動拡張OFF、かつ、UNDO保存の保証が無効のため、この値は無視されます。
検証シナリオ
●パターン1
削除件数を指定せず、全データを一気に削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まらないパターン)
手順1-1.データ削除前のUNDO情報を確認
手順1-2.データを一気に削除
手順1-3.データ削除後のUNDO情報を確認
●パターン2
削除件数を指定し、全データを複数回に分けて削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まるパターン)
手順2-1.データ削除前のUNDO情報を確認
手順2-2.データを50,000件(約5MB)ずつ削除
手順2-3.データ削除後のUNDO情報を確認
検証結果
●パターン1
削除件数を指定せず、全データを一気に削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まらないパターン)
→全データ削除の途中でORA-30036が発生した。
●パターン2
削除件数を指定し、全データを複数回に分けて削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まるパターン)
→ORA-30036は発生せず、全データを削除できた。
検証ログ
●パターン1
削除件数を指定せず、全データを一気に削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まらないパターン)
SQL> --UNDO表領域の使用可能サイズと使用可能ブロック数
SQL> SELECT
2 TABLESPACE_NAME
3 , BYTES / 1024 / 1024 as TOTAL_MB
4 , BLOCKS
5 , USER_BYTES / 1024 / 1024 as AVAIL_MB
6 , USER_BLOCKS as AVAIL_BLKS
7 FROM
8 DBA_DATA_FILES
9 WHERE
10 TABLESPACE_NAME = 'UNDOTBS1';
TABLESPACE_NAME TOTAL_MB BLOCKS AVAIL_MB AVAIL_BLKS
------------------------- ------------------ ---------- ---------- ----------
UNDOTBS1 20.0 2560 19 2432
★実際ユーザーが使用可能サイズ(AVAIL_MB)は19MB、使用可能ブロック数(AVAIL_BLKS)は2432です。
SQL> --UNDO表領域(ACTIVE/UNEXPIREDのUNDOデータ)の使用状況
SQL> SELECT
2 DUE.TABLESPACE_NAME
3 , ROUND(DDF.TOTAL_BYTES / 1024 / 1024, 1) as TOTAL_MB
4 , ROUND(DUE.USED_BYTES / 1024 / 1024, 1) as USED_MB
5 , ROUND((DUE.USED_BYTES / DDF.TOTAL_BYTES) * 100, 2) as RATIO_PCT
6 FROM
7 (
8 SELECT
9 TABLESPACE_NAME
10 , SUM(BYTES) AS USED_BYTES
11 FROM
12 DBA_UNDO_EXTENTS
13 WHERE
14 STATUS IN('ACTIVE', 'UNEXPIRED')
15 AND TABLESPACE_NAME = 'UNDOTBS1'
16 GROUP BY
17 TABLESPACE_NAME
18 ) DUE,
19 (
20 SELECT
21 TABLESPACE_NAME
22 , SUM(BYTES) AS TOTAL_BYTES
23 FROM
24 DBA_DATA_FILES
25 WHERE
26 TABLESPACE_NAME = 'UNDOTBS1'
27 GROUP BY
28 TABLESPACE_NAME
29 ) DDF
30 WHERE
31 DUE.TABLESPACE_NAME = DDF.TABLESPACE_NAME
32 ORDER BY
33 DUE.TABLESPACE_NAME;
TABLESPACE_NAME TOTAL_MB USED_MB RATIO_PCT
------------------------- ------------------ ------------------ ---------
UNDOTBS1 20.0 0.6 3.10
★UNDO表領域の使用サイズ(USED_MB)は0.6MBです。
SQL> --UNDOデータのステータスごとのエクステント使用状況
SQL> SELECT
2 TABLESPACE_NAME
3 , STATUS
4 , COUNT(*) as USED_EXTS
5 , SUM(BYTES) / 1024 / 1024 as USED_MB
6 , SUM(BLOCKS) as USED_BLKS
7 FROM
8 DBA_UNDO_EXTENTS
9 GROUP BY
10 TABLESPACE_NAME
11 , STATUS
12 ORDER BY
13 TABLESPACE_NAME
14 , STATUS;
TABLESPACE_NAME STATUS USED_EXTS USED_MB USED_BLKS
------------------------- -------------------- ---------- ------------------ ----------
UNDOTBS1 EXPIRED 10 0.6 80
UNDOTBS1 UNEXPIRED 10 0.6 80
★EXPIRED/UNEXPIREDのUNDOデータがあり、それぞれ0.6MBずつ使用しています。
SQL> --UNDOセグメントの使用状況
SQL> SELECT
2 TABLESPACE_NAME
3 , SUM(BLOCKS) as USED_BLKS
4 , ROUND(SUM(BYTES) / 1024 / 1024, 1) as USED_MB
5 , SUM(EXTENTS) as USED_EXTS
6 FROM
7 DBA_SEGMENTS
8 WHERE
9 TABLESPACE_NAME = 'UNDOTBS1'
10 GROUP BY
11 TABLESPACE_NAME;
TABLESPACE_NAME USED_BLKS USED_MB USED_EXTS
------------------------- ---------- ------------------ ----------
UNDOTBS1 160 1.3 20
★使用ブロック数(USED_BLKS)は160、使用サイズ(USED_MB)は1.3MB、使用エクステント数(USED_EXTS)は20です。
SQL> --UNDOブロックの生成状況
SQL> SELECT
2 TO_CHAR(BEGIN_TIME,'YYYY-MM-DD HH24:MI:SS') BEGIN_TM
3 , TO_CHAR(END_TIME,'YYYY-MM-DD HH24:MI:SS') END_TM
4 , UNDOBLKS
5 , SSOLDERRCNT
6 , NOSPACEERRCNT
7 , TUNED_UNDORETENTION
8 FROM
9 V$UNDOSTAT
10 ORDER BY
11 END_TM DESC;
BEGIN_TM END_TM UNDOBLKS SSOLDERRCNT NOSPACEERRCNT TUNED_UNDORETENTION
-------------------- -------------------- ---------- ----------- ------------- -------------------
2023-07-28 16:10:00 2023-07-28 16:12:11 0 0 0 29847
★データ削除前のUNDOブロック生成数(UNDOBLKS)は0です(UNDOブロックは生成されていない)
手順1-2.データを一気に削除
SQL> --データ削除前の件数確認
SQL> SELECT COUNT(*) FROM APP_TBL;
COUNT(*)
----------
300000
★APP_TBL表には300,000件(約30MB)のデータが入っています。
SQL> --データ削除
SQL> DELETE FROM APP_TBL;
DELETE FROM APP_TBL
*
ERROR at line 1:
ORA-30036: unable to extend segment by 8 in undo tablespace 'UNDOTBS1'
★削除件数を指定せず、APP_TBL表から300,000件(約30MB)のデータを一気に削除します(約30MBのUNDOデータが生成されます)
DELETE文で生成されたUNDOデータはUNDO表領域に収まらないため、ORA-30036が発生する想定です。
DELETE文実行後、しばらくしてORA-30036が発生しました。
SQL> --データ削除後の件数確認
SQL> SELECT COUNT(*) FROM APP_TBL;
COUNT(*)
----------
300000
★データ削除に失敗したため、APP_TBL表のデータ件数も変わっていません。
手順1-3.データ削除後のUNDO情報を確認
※UNDO情報の確認SQLは手順1-1で使用したものと同じです。
SQL> --UNDO表領域(UNDOデータのステータスACTIVE/UNEXPIRED)の使用状況
TABLESPACE_NAME TOTAL_MB USED_MB RATIO_PCT
------------------------- ------------------ ------------------ ---------
UNDOTBS1 20.0 18.6 93.10
★UNDO表領域の使用サイズ(USED_MB)は18.6MBです。
SQL> --UNDOデータのステータスごとのエクステント使用状況
TABLESPACE_NAME STATUS USED_EXTS USED_MB USED_BLKS
------------------------- --------- ---------- ------------------ ----------
UNDOTBS1 EXPIRED 6 0.4 48
UNDOTBS1 UNEXPIRED 103 18.6 2384
★EXPIRED/UNEXPIREDのUNDOデータが合計19MB使用しています。手順1-1で確認した使用可能サイズ(19MB)に達しています。
SQL> --UNDOセグメントの使用状況
TABLESPACE_NAME USED_BLKS USED_MB USED_EXTS
------------------------- ---------- ------------------ ----------
UNDOTBS1 2432 19.0 64
★使用ブロック数と使用サイズが、手順1-1で確認した使用可能ブロック数(2432)と使用可能サイズ(19MB)に達しており、
UNDOセグメントが枯渇していたということが分かります。
SQL> --UNDOブロック生成状況
BEGIN_TM END_TM UNDOBLKS SSOLDERRCNT NOSPACEERRCNT TUNED_UNDORETENTION
-------------------- -------------------- ---------- ----------- ------------- -------------------
2023-07-28 16:10:00 2023-07-28 16:14:37 2282 0 1 202
★データ削除時、UNDOブロックが2,282ブロック(約18MB)生成されたタイミングでUNDOセグメント拡張に失敗したため、
NOSPACEERRCNT列は1になりました(拡張に失敗するとインクリメントされる)
●パターン2
削除件数を指定し、全データを複数回に分けて削除(データ削除時に生成されたUNDOデータがUNDO表領域に収まるパターン)
※事前に検証用UNDO表領域を再作成しています。
手順2-1.データ削除前のUNDO情報を確認
※UNDO情報の確認SQLは手順1-1で使用したものと同じです。
SQL> --UNDO表領域(UNDOデータのステータスACTIVE/UNEXPIRED)の使用状況
TABLESPACE_NAME TOTAL_MB USED_MB RATIO_PCT
------------------------- ------------------ ------------------ ---------
UNDOTBS1 20.0 0.6 3.10
★UNDO表領域の使用サイズ(USED_MB)は0.6MBです。
SQL> --UNDOデータのステータスごとのエクステント使用状況
TABLESPACE_NAME STATUS USED_EXTS USED_MB USED_BLKS
------------------------- -------------------- ---------- ------------------ ----------
UNDOTBS1 EXPIRED 10 0.6 80
UNDOTBS1 UNEXPIRED 10 0.6 80
★EXPIRED/UNEXPIREDのUNDOデータがあり、それぞれ0.6MBずつ使用しています。
SQL> --UNDOセグメントの使用状況
TABLESPACE_NAME USED_BLKS USED_MB USED_EXTS
------------------------- ---------- ------------------ ----------
UNDOTBS1 160 1.3 20
★使用ブロック数(USED_BLKS)は160、使用サイズ(USED_MB)は1.3MB、使用エクステント数(USED_EXTS)は20です。
SQL> --UNDOブロック生成状況
BEGIN_TM END_TM UNDOBLKS SSOLDERRCNT NOSPACEERRCNT TUNED_UNDORETENTION
-------------------- -------------------- ---------- ----------- ------------- -------------------
2023-07-28 16:30:00 2023-07-28 16:33:27 0 0 0 1043
2023-07-28 16:20:00 2023-07-28 16:30:00 30 0 0 949
2023-07-28 16:10:00 2023-07-28 16:20:00 2287 0 1 486
★データ削除前のUNDOブロック生成数(UNDOBLKS)は0です(UNDOブロックは生成されていない)
手順2-2.データを50,000件(約5MB)ずつ削除
SQL> --データ削除前の件数確認
SQL> SELECT COUNT(*) FROM APP_TBL;
COUNT(*)
----------
300000
★APP_TBL表には300,000件(約30MB)のデータが入っています。
SQL> --データ削除
SQL> DELETE FROM APP_TBL WHERE ROWNUM <= 50000;
50000 rows deleted.
SQL> COMMIT;
Commit complete.
★1回のDELETE文で50,000件(約5MB)ずつ削除し、コミットします。この作業を全データ分(合計6回)繰り返します。
1回のDELETE文で生成されたUNDOデータはUNDO表領域に収まり、コミットすることでUNDOデータを上書きできる状態にするため、ORA-30036は発生しない想定です。
SQL> --データ削除後の件数確認(DELETE&COMMITを6回繰り返した後)
SQL> SELECT COUNT(*) FROM APP_TBL;
COUNT(*)
----------
0
★全データが削除されました。
手順2-3.データ削除後のUNDO情報を確認
※UNDO情報の確認SQLは手順1-1で使用したものと同じです。
SQL> --UNDO表領域(UNDOデータのステータスACTIVE/UNEXPIRED)の使用状況
TABLESPACE_NAME TOTAL_MB USED_MB RATIO_PCT
------------------------- ------------------ ------------------ ---------
UNDOTBS1 20.0 18.7 93.40
★UNDO表領域の使用サイズ(USED_MB)は18.7MBです。
手順1-3同様にUNDO表領域の使用状況を見るだけでは判断できないため、エクステント使用状況やセグメント使用状況も確認します。
SQL> --UNDOデータのステータスごとのエクステント使用状況
TABLESPACE_NAME STATUS USED_EXTS USED_MB USED_BLKS
------------------------- -------------------- ---------- ------------------ ----------
UNDOTBS1 EXPIRED 5 0.3 40
UNDOTBS1 UNEXPIRED 104 18.7 2392
★EXPIRED/UNEXPIREDのUNDOデータが合計19MB使用しています。今回も手順1-1で確認した使用可能サイズ(19MB)に達しています。
SQL> --UNDOセグメントの使用状況
TABLESPACE_NAME USED_BLKS USED_MB USED_EXTS
------------------------- ---------- ------------------ ----------
UNDOTBS1 2432 19.0 109
★使用ブロック数と使用サイズが、手順1-1で確認した使用可能ブロック数(2432)と使用可能サイズ(19MB)に達しており、
今回もUNDOセグメントが枯渇していたということが分かります。
しかし、使用エクステント数は109(ORA-30036発生時は64)となっており、UNDOセグメントが枯渇間近になりながらもエクステントを使い回せていたということが分かります。
SQL> --UNDOブロック生成状況
BEGIN_TM END_TM UNDOBLKS SSOLDERRCNT NOSPACEERRCNT TUNED_UNDORETENTION
-------------------- -------------------- ---------- ----------- ------------- -------------------
2023-07-28 16:30:00 2023-07-28 16:35:40 7898 0 0 74
2023-07-28 16:20:00 2023-07-28 16:30:00 30 0 0 949
2023-07-28 16:10:00 2023-07-28 16:20:00 2287 0 1 486
参考資料
オラクルマスター教科書 Silver DBA Oracle Database Administration I
https://blogs.oracle.com/otnjp/post/shibacho-028