梅雨空の続くある日、ora-1652が発生して業務影響が出ていると連絡がありました。
何年も前から稼働している本番環境で、構成は以下の通りです。
絵で見てわかるOracleの仕組み 新装版 [ 小田 圭二 ]
- 価格: 2530 円
- 楽天で詳細を見る
エラーの原因と対処法はマニュアルを見なくてもコマンドラインで確認できます。
$ oerr ora 1652
01652, 00000, "unable to extend temp segment by %s in tablespace %s"
// *Cause: Failed to allocate an extent of the required number of blocks for
// a temporary segment in the tablespace indicated.
// *Action: Use ALTER TABLESPACE ADD DATAFILE statement to add one or more
// files to the tablespace indicated.
一時表領域不足によるエラーで、回避策は当然ながら一時表領域の拡張になります。
一時表領域は約30GBで、同サイズのファイルを追加して2倍の領域にする事で対処してもらいました。
一時表領域の使用率確認は以下のようなSQLで行います。
各カラムの意味ですが、
ALLOCATED_SPACE:現在割り当てられ、使用されている領域と、現在割り当てられ、再利用できる領域を含む、割り当てられた領域の合計量(バイト)
FREE_SPACE:現在割り当てられ、再利用できる領域と、現在割り当てられていない領域を含む、使用可能空き領域の合計量(バイト)
となるので、ALLOCATED_SPACE+FREE_SPACE>=TABLESPACE_SIZEとなります。
以下のSQLでは 再利用不可の領域サイズ÷表領域サイズ を"ts_used_%"としています。
SQL> select tablespace_name,
2 round(TABLESPACE_SIZE/1024/1024,1) tablespace_MB,
3 round(ALLOCATED_SPACE/1024/1024,1) used_MB,
4 round(FREE_SPACE/1024/1024,1) free_MB,
5 lpad(round((TABLESPACE_SIZE-FREE_SPACE)/(TABLESPACE_SIZE)*100,2)||'%',10,' ') "ts_used_%"
6 from dba_temp_free_space;
TABLESPACE_NAME ABLESPACE_MB USED_MB FREE_MB ts_used_%
------------------------------ ------------- ---------- ---------- ----------
TEMP 50 15 49 6.67%
ちなみに、通常の表領域使用率は以下のSQLで取得します。
SQL> select total.TABLESPACE_NAME tsname,
D nfrags,
C/1024/1024 mxfrag,
A/1024/1024 totsiz,
B/1024/1024 avasiz,
(1-nvl(B,0)/A)*100 pctusd
from
(select sum(bytes) A,
tablespace_name
from dba_data_files
group by tablespace_name) TOTAL,
(select sum(bytes) B,
max(bytes) C,
count(bytes) D,
tablespace_name
from dba_free_space
group by tablespace_name) FREE
where
total.TABLESPACE_NAME=free.TABLESPACE_NAME(+);
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
TSNAME NFRAGS MXFRAG TOTSIZ AVASIZ PCTUSD
------------------------------ ---------- ---------- ---------- ---------- ----------
SYSAUX 196 2890 5000 3945.375 21.0925
UNDOTBS1 41 3968 8000 5499.75 31.253125
USERS 1 3.3125 5 3.3125 33.75
SYSTEM 2 7 1210 7.125 99.411157
※UNDO表領域については上記の使用率ではなく、(v$undostat.ACTIVEBLKS+v$undostat.UNEXPIREDBLKS)÷UNDO表領域サイズで計算します。
エラーは発生しなくなり業務影響も無くなったので、次に原因調査をします。
必要となるのは障害発生前後の時間帯も含んだAWRレポートと、ASH(ActiveSessionHistory)のダンプファイルです。
ASHのダンプは以下のような手順で取得します。
まず、 sys 以外のDBAロールを付与されたユーザ(例:system)でコピーテーブルを作成します。
SQL> conn system/******
SQL> create table exp_hist_active_sess_history
as select * from dba_hist_active_sess_history
where sample_time
between to_timestamp('16-10-12 21:30:00','YY-MM-DD HH24:MI:SS')
and to_timestamp('16-10-12 21:30:00','YY-MM-DD HH24:MI:SS');
作成したコピーテーブルをエクスポートします。
$ expdp system/****** directory=test_dir dumpfile=exp_ash.dmp tables=exp_hist_active_sess_history
コピーテーブルを作成するのはsysのオブジェクトはエクスポートできないからで、当然、コピーテーブルはsys以外のユーザで作成する必要があります。
上記手順で本番環境からエクスポートしたデータを、検証環境にインポートして、一時表領域を大量に使用しているSQLを確認します。
SQL> select distinct SQL_ID from exp_hist_active_sess_history where TEMP_SPACE_ALLOCATED >=50*1024*1024;
その結果、一時表領域を50MB以上使用していたのはある特定の一つのSQLである事、障害発生時間帯に顕著に使用量が増えている事が判明しました。
障害発生時とその前後の平常時でSQL_PLAN_HASH_VALUEが同じなので、実行計画は変わっていない事も判ります。
被疑SQLは判明したので、次にこのSQLがその時間帯に限って大量に一時表領域を使用した原因を探ります。
まずAWRの処理時間の長いSQLから、負荷の高い時間帯に特に長時間かかったSQLをピックアップしてみました。
障害発生前
Total | Per Execution | Percentage of Total | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
SQL Id | Elapsed (s) | CPU (s) | IOWait (s) | Gets | Reads | Rows | Cluster (s) | Execs | Elapsed (s) | CPU (s) | IOWait (s) | Gets | Reads | Rows | Cluster (s) | DB time | DB CPU | IO Wait | Gets | Reads | Cluster | Execs | SQL Text |
yyyyyy | 5,878.15 | 5,024.28 | 171.46 | 939,177,081 | 13,532,704 | 14,819 | 560.16 | 11,139 | 0.53 | 0.45 | 0.02 | 84,314.31 | 1,214.89 | 1.33 | 0.05 | 28.43 | 28.73 | 0.15 | 31.20 | 17.37 | 32.80 | 0.63 | WITH AAA AS ( ... |
xxxxxx | 5,678.55 | 4,774.27 | 708.05 | 498,777,432 | 34,474,420 | 2,790 | 71.12 | 885 | 6.42 | 5.39 | 0.80 | 563,590.32 | 38,954.15 | 3.15 | 0.08 | 27.46 | 27.30 | 0.62 | 16.57 | 44.25 | 4.16 | 0.05 | WITH SSS AS ... |
zzzzzz | 517.33 | 488.52 | 11.53 | 37,859,990 | 409,268 | 18,680 | 1.69 | 12,402 | 0.04 | 0.04 | 0.00 | 3,052.73 | 33.00 | 1.51 | 0.00 | 2.50 | 2.79 | 0.01 | 1.26 | 0.53 | 0.10 | 0.70 | WITH GGG AS ( SELECT GGG... |
障害発生時
Total | Per Execution | Percentage of Total | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
SQL Id | Elapsed (s) | CPU (s) | IOWait (s) | Gets | Reads | Rows | Cluster (s) | Execs | Elapsed (s) | CPU (s) | IOWait (s) | Gets | Reads | Rows | Cluster (s) | DB time | DB CPU | IO Wait | Gets | Reads | Cluster | Execs | SQL Text |
xxxxxx | 598,929.85 | 11,437.04 | 38,426.76 | 1,054,682,763 | 65,319,166 | 5,202 | 89,669.01 | 2,895 | 206.88 | 3.95 | 13.27 | 364,311.84 | 22,562.75 | 1.80 | 30.97 | 42.90 | 32.20 | 0.58 | 20.38 | 48.20 | 51.11 | 0.06 | WITH SSS AS ... |
yyyyyy | 346,542.90 | 12,682.99 | 17,382.04 | 2,337,263,005 | 33,409,125 | 34,896 | 43,802.27 | 27,913 | 12.42 | 0.45 | 0.62 | 83,733.85 | 1,196.90 | 1.25 | 1.57 | 24.82 | 35.71 | 0.26 | 45.17 | 24.65 | 24.96 | 0.57 | WITH AAA AS ( ... |
zzzzzz | 322,739.86 | 1,720.68 | 2,129.13 | 136,209,746 | 1,473,010 | 56,316 | 27,983.22 | 45,095 | 7.16 | 0.04 | 0.05 | 3,020.51 | 32.66 | 1.25 | 0.62 | 23.12 | 4.84 | 0.03 | 2.63 | 1.09 | 15.95 | 0.92 | WITH GGG AS ( SELECT GGG... |
X,Y,Zの3つのSQLで、平常時に比べて処理時間が長くなっています。
このうち、ASHで確認した被疑SQLはXになります。
特にXについては処理件数が約3倍、1実行当たりの処理時間は30倍以上と、顕著に増加しています。
更に「Top SQL with Top Row Sources」で確認すると、X,Y,Z共に「enq: SS - contention」で長時間待機しているので、ソート・セグメント(この場合は一時表領域)で競合が発生し、待機した事になります。
SQL ID | Plan Hash | Executions | % Activity | Row Source | % Row Source | Top Event | % Event | SQL Text |
---|---|---|---|---|---|---|---|---|
xxx | 866674186 | 3032 | 42.31 | SELECT STATEMENT | 38.31 | enq: SS - contention | 29.57 | WITH SSS AS ... |
TABLE ACCESS - FULL | 2.13 | db file scattered read | 2.10 | |||||
LOAD AS SELECT | 1.28 | CPU + Wait for CPU | 0.72 | |||||
yyy | 1102321024 | 6792 | 24.58 | SELECT STATEMENT | 21.64 | enq: SS - contention | 18.33 | WITH AAA AS ( ... |
TABLE ACCESS - FULL | 1.33 | CPU + Wait for CPU | 0.89 | |||||
zzz | 4180003833 | 6228 | 22.81 | SELECT STATEMENT | 22.50 | enq: SS - contention | 19.90 | WITH GGG AS ( SELECT GGG... |
Y,Zについては一時表領域の使用量が少ないので、Xが一時表領域を食い潰した結果、ソート・セグメントが使用できずに待機してしまったようです。
一時表領域枯渇により、1実行当たりの処理時間がソート領域待機によって増え、領域解放までに時間がかかる事で更に領域不足を加速させたと考えられます。
また、CPUやメモリの使用率には余裕があったので、業務影響が出たのもXの実行数が増えて一時表領域を食い潰した事による待機が原因でした。
Xではテーブルのフルスキャンが行われているので、その点が改善できれば一時表領域の使用量が減る可能性がある事をAP開発元に伝えて、今回の調査は終了となりました。