Oracleを運用していると、ある日突然「TEMP表領域がいっぱいになった」「ORA-01652が発生した」という事態に直面することがあります。TEMP表領域(一時表領域)は、ソートやハッシュ結合などで一時的に使用される領域ですが、適切に管理しないと肥大化してシステム障害の原因になります。
この記事では、TEMP表領域が肥大化する根本原因から、確認SQL・RESIZE・再作成による具体的なクリーンアップ方法、ORA-01652エラーへの対処、PGAチューニングによる予防策まで、実務で役立つ手順を体系的に解説します。
- TEMP表領域の仕組みと役割
- 肥大化の主な原因(ソート・ハッシュ結合・PGA不足など)
- v$sort_usage・v$temp_space_headerを使った使用状況確認SQL
- セッション強制終了・RESIZE・再作成の3つのクリーンアップ手順
- ORA-01652エラーの対処法
- PGA_AGGREGATE_TARGETによる肥大化予防策
TEMP表領域とは何か
TEMP表領域(一時表領域)は、Oracleがクエリを実行する際に一時的なデータを格納するための専用領域です。通常のデータファイル(datafile)とは異なり、TEMPFILEとして管理されます。
TEMP表領域が使用される主なケース
| 操作 | 説明 |
|---|---|
| ORDER BY / GROUP BY | ソート処理でPGAに収まらない場合にディスクへスピルアウト |
| ハッシュ結合(Hash Join) | ハッシュテーブルがPGAを超えた際にTEMPを使用 |
| インデックス再構築 | CREATE INDEX・REBUILD時に一時領域を大量消費 |
| 一時表(Global Temporary Table) | セッション/トランザクション単位の一時表データ |
| サブクエリのマテリアライズ | 複雑なSQLの中間結果を一時保存 |
PGAとTEMPの関係
OracleはまずPGA(Program Global Area)と呼ばれるメモリ領域でソートを試みます。PGAの容量(PGA_AGGREGATE_TARGETで制御)を超えた場合、残りの処理をTEMP表領域(ディスク)に「スピルアウト」して処理します。
通常、TEMP表領域はクエリ終了後に自動的に解放されます。しかし、セッションが異常終了した場合や、ソートセグメントが残ったままになるケースでは、使用済みとして予約されたブロックが残ることがあります。
TEMP表領域が肥大化する主な原因
TEMP表領域が予想以上に大きくなる原因は複数あります。それぞれの原因を理解することで、適切な対策が取れます。
1. 大量データのソート・ハッシュ結合
数百万件以上のデータをORDER BYやGROUP BYで処理する場合、PGAに収まらず大量のTEMP領域を消費します。特にバッチ処理や夜間のETL処理で起きやすいパターンです。
2. インデックスの再構築
ALTER INDEX ... REBUILDは内部的にソートを伴うため、大きなインデックスほどTEMP消費量が増大します。オンライン再構築(ONLINEオプション)でも同様です。
3. PGA_AGGREGATE_TARGETの不足
PGAのメモリが小さく設定されていると、小さなソート処理でもすぐにTEMPへスピルアウトします。多数のセッションが同時に処理を行うと、TEMP消費が累積して肥大化します。
4. セッション異常終了による残存
通常はセッション終了とともにTEMPセグメントが解放されますが、ネットワーク切断・プロセスクラッシュなどの異常終了では、OSレベルのセッションは消えてもOracleのTEMPセグメントが残存することがあります。
v$temp_space_headerで確認できる
used_blocksには、すでに処理が終わったが解放されていないブロックも含まれます。これは正常動作ですが、新しい割り当てが必要な場合は再利用されます。問題は、OSレベルでファイルサイズが縮小しない点です。5. 並列クエリ(Parallel Query)
並列度(PARALLEL)を高く設定したクエリは、複数のパラレルスレーブが同時にTEMPを使用するため、消費量が並列度に比例して増大します。
TEMP使用状況の確認SQL
クリーンアップを行う前に、現在のTEMP使用状況を正確に把握することが重要です。以下のSQLでセッション別・表領域全体の使用量を確認します。
セッション別TEMP使用量(v$sort_usage)
-- セッション別TEMP使用量(MB単位)
SELECT
s.sid,
s.serial#,
s.username,
s.status,
u.tablespace,
u.segtype,
ROUND(u.blocks * 8192 / 1024 / 1024, 2) AS used_mb,
s.sql_id
FROM v$sort_usage u
JOIN v$session s ON u.session_addr = s.saddr
ORDER BY used_mb DESC;
sid / serial#:セッションを一意に識別するIDsegtype:SORT(ソート)またはHASH(ハッシュ結合)などused_mb:そのセッションが使用中のMB数sql_id:TEMPを消費している現在のSQL
TEMP表領域全体の使用量(v$tempseg_usage)
-- TEMP表領域全体の使用量集計
SELECT
tablespace_name,
ROUND(SUM(bytes) / 1024 / 1024, 2) AS used_mb
FROM v$tempseg_usage
GROUP BY tablespace_name;
TEMP表領域の空き容量確認(v$temp_space_header)
-- TEMP表領域のブロック使用状況
SELECT
tablespace_name,
file#,
total_blocks,
used_blocks,
free_blocks,
ROUND(used_blocks / total_blocks * 100, 1) AS used_pct
FROM v$temp_space_header
ORDER BY tablespace_name, file#;
TEMPファイルのサイズ確認(DBA_TEMP_FILES)
-- TEMPFILEのサイズと自動拡張設定
SELECT
file_name,
tablespace_name,
ROUND(bytes / 1024 / 1024, 0) AS size_mb,
ROUND(maxbytes / 1024 / 1024, 0) AS maxsize_mb,
autoextensible
FROM dba_temp_files
ORDER BY tablespace_name;
クリーンアップ方法1:セッションを強制終了
現在進行中のセッションが大量のTEMPを消費している場合、そのセッションを強制終了することでTEMPを解放できます。
手順1:対象セッションを特定する
-- TEMPを大量消費しているセッションとSQLを特定
SELECT
s.sid,
s.serial#,
s.username,
s.osuser,
s.program,
ROUND(u.blocks * 8192 / 1024 / 1024, 2) AS temp_mb,
q.sql_text
FROM v$sort_usage u
JOIN v$session s ON u.session_addr = s.saddr
LEFT JOIN v$sql q ON s.sql_id = q.sql_id AND s.sql_child_number = q.child_number
ORDER BY temp_mb DESC;
手順2:セッションをKILLする
-- セッションを強制終了(SIDとSERIAL#は手順1で確認した値) ALTER SYSTEM KILL SESSION '123,456' IMMEDIATE;
IMMEDIATEを付けると、Oracleはセッションを即座に切断し、使用中のリソース(ロック・TEMPセグメント)を解放します。IMMEDIATEなしの場合は、次にそのセッションがOracleと通信したときに終了します。急ぎの場合は必ずIMMEDIATEを付けてください。セッション強制終了は、そのセッションが実行中のトランザクションをすべてロールバックします。業務アプリケーションのセッションを誤ってKILLすると、処理中データが失われる可能性があります。
username・program・osuserを必ず確認してから実行してください。クリーンアップ方法2:TEMPFILEのリサイズ(RESIZE)
TEMPファイルが必要以上に大きくなっている場合、ALTER DATABASE TEMPFILE ... RESIZEでファイルサイズを縮小できます。ただし、使用中のブロックが含まれている場合はエラーになります。
TEMPFILEのパスを確認する
-- TEMPFILEのパスとサイズを確認 SELECT file_name, ROUND(bytes/1024/1024,0) AS current_mb FROM dba_temp_files;
TEMPFILEをリサイズする
-- TEMPFILEを512MBにリサイズ(パスは環境に合わせて変更) ALTER DATABASE TEMPFILE '/u01/oradata/ORCL/temp01.dbf' RESIZE 512M;
「ORA-03297: file contains used data beyond requested RESIZE value」が出た場合は、指定サイズより後方にまだ使用中(または予約済み)のブロックが存在することを意味します。その場合はいったんセッションを終了させてから再試行するか、次の「再作成」の方法を使ってください。
RESIZE後のサイズ確認
-- リサイズ後の確認 SELECT file_name, ROUND(bytes/1024/1024,0) AS new_mb FROM dba_temp_files;
クリーンアップ方法3:一時表領域の再作成(確実な方法)
RESIZEが失敗する場合や、確実にTEMP領域を初期化したい場合は、新しい一時表領域を作成してデフォルトを切り替え、古い表領域を削除する方法が最も確実です。
手順1:新しい一時表領域を作成する
-- 新しい一時表領域TEMP2を作成(サイズは環境に合わせて調整)
CREATE TEMPORARY TABLESPACE temp2
TEMPFILE '/u01/oradata/ORCL/temp02.dbf' SIZE 1G AUTOEXTEND ON;
手順2:データベースのデフォルト一時表領域を変更する
-- データベース全体のデフォルトTEMPをTEMP2に変更 ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp2; -- 変更後の確認 SELECT property_value FROM database_properties WHERE property_name = 'DEFAULT_TEMP_TABLESPACE';
手順3:特定ユーザーのTEMPが旧表領域のままの場合は変更する
-- TEMPを指定しているユーザーを確認 SELECT username, temporary_tablespace FROM dba_users WHERE temporary_tablespace = 'TEMP'; -- ユーザーのデフォルトTEMPを変更 ALTER USER scott TEMPORARY TABLESPACE temp2;
手順4:古い一時表領域を削除する
-- 旧TEMPを削除(INCLUDING CONTENTS AND DATAFILESでファイルも削除) DROP TABLESPACE temp INCLUDING CONTENTS AND DATAFILES; -- 削除確認 SELECT tablespace_name FROM dba_tablespaces WHERE tablespace_name LIKE 'TEMP%';
一時表領域の再作成手順のポイントをまとめます。
- 必ず新規作成→デフォルト変更→削除の順で実施する(逆順は不可)
- デフォルトTEMP変更後もユーザー個別にTEMPが設定されている場合は別途変更が必要
INCLUDING DATAFILESを付けるとOSのファイルも自動削除される(ファイルシステムの空き確保に有効)- 新TEMPのサイズは、通常時のTEMP使用量の1.5〜2倍を目安に設定する
肥大化の予防策
TEMP表領域の肥大化を予防するには、SQLの最適化とOracleパラメータの適切な設定が重要です。
1. PGA_AGGREGATE_TARGETの増加
PGAが十分に大きければ、TEMP表領域へのスピルアウトを減らせます。システムのメモリ量に応じて適切な値を設定します。
-- 現在のPGA_AGGREGATE_TARGETを確認 SHOW PARAMETER pga_aggregate_target; -- PGA_AGGREGATE_TARGETを2GBに増加(再起動不要) ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=BOTH;
2. WORKAREA_SIZE_POLICYをAUTOに確認・設定
-- WORKAREA_SIZE_POLICYの確認(AUTOが推奨) SHOW PARAMETER workarea_size_policy; -- AUTOに設定(PGAの自動管理を有効化) ALTER SYSTEM SET workarea_size_policy = AUTO SCOPE=BOTH;
AUTOに設定すると、OracleはPGA_AGGREGATE_TARGETの範囲内で各セッションのソート・ハッシュ結合用メモリを自動的に管理します。MANUALの場合はSORT_AREA_SIZEなどを個別に設定する必要があり、チューニングが複雑になります。特別な理由がない限りAUTOを推奨します。3. SQLの最適化
不要なORDER BYを削除する、適切なインデックスを作成してフルスキャンを排除するなど、根本的なSQLのチューニングが最も効果的です。
-- TEMPを多く消費しているSQL(実行計画でSORT操作を確認)
SELECT sql_id, sql_text, executions,
ROUND(disk_reads / NULLIF(executions,0), 0) AS disk_reads_per_exec
FROM v$sql
WHERE disk_reads > 10000
ORDER BY disk_reads DESC
FETCH FIRST 20 ROWS ONLY;
4. 定期的な監視スクリプト
TEMP使用量を定期的に監視し、閾値を超えたらアラートを出す仕組みを整えることで、肥大化を早期に検知できます。
-- TEMP使用率が80%を超えたらアラート対象として抽出
SELECT tablespace_name,
ROUND(used_blocks / total_blocks * 100, 1) AS used_pct,
free_blocks
FROM v$temp_space_header
WHERE used_blocks / total_blocks > 0.8;
ORA-01652エラーの対処法
ORA-01652: unable to extend temp segment by N in tablespace TEMPは、TEMP表領域の空き領域が不足してセグメントを拡張できないエラーです。
エラー発生時の即時対処
方法A:既存TEMPFILEを拡張する
-- 既存TEMPFILEのサイズを拡張
ALTER DATABASE TEMPFILE '/u01/oradata/ORCL/temp01.dbf' RESIZE 4G;
-- または自動拡張をONにする
ALTER DATABASE TEMPFILE '/u01/oradata/ORCL/temp01.dbf'
AUTOEXTEND ON MAXSIZE 8G;
方法B:TEMPFILEを追加する
-- 既存TEMP表領域に新しいTEMPFILEを追加
ALTER TABLESPACE temp
ADD TEMPFILE '/u01/oradata/ORCL/temp02.dbf' SIZE 2G AUTOEXTEND ON;
エラーが繰り返す場合は、単なる容量不足ではなく、以下の可能性を検討してください。
- 特定のSQL/バッチ処理がTEMPを異常消費している(v$sort_usageで特定)
- PGA設定が小さすぎてすべての処理がTEMPにスピルアウトしている
- 並列度が高すぎるクエリが実行されている
よく使うSQL一覧
| 目的 | ビュー/コマンド | 備考 |
|---|---|---|
| セッション別TEMP使用量確認 | v$sort_usage + v$session | TEMP消費元SQLも取得可能 |
| TEMP表領域全体の使用量 | v$tempseg_usage | MB単位で集計 |
| ブロックレベルの使用状況 | v$temp_space_header | used_pct計算に使用 |
| TEMPファイルのサイズ・設定 | dba_temp_files | 自動拡張の確認 |
| セッション強制終了 | ALTER SYSTEM KILL SESSION | IMMEDIATEを推奨 |
| TEMPファイルのリサイズ | ALTER DATABASE TEMPFILE RESIZE | 使用中ブロックがあるとエラー |
| 新TEMP表領域の作成 | CREATE TEMPORARY TABLESPACE | デフォルト変更と組み合わせる |
| デフォルトTEMPの変更 | ALTER DATABASE DEFAULT TEMPORARY TABLESPACE | 全ユーザーに影響 |
| 旧TEMP表領域の削除 | DROP TABLESPACE … INCLUDING DATAFILES | OSファイルも削除 |
| PGA設定変更 | ALTER SYSTEM SET pga_aggregate_target | 再起動不要(SCOPE=BOTH) |
FAQ
v$sort_usageでどのSQLが大量消費しているかを特定し、SQLチューニングやPGA増加と組み合わせることで、恒久的な改善が期待できます。v$sort_usageとv$sessionをJOINしてsql_idを取得し、そのsql_idをv$sqlで検索するとSQL文が確認できます。さらにDBMS_XPLAN.DISPLAY_CURSORで実行計画を確認し、SOPTやHASH JOINのuses-temp-spaceの有無を確認します。AWRレポートの「Top SQL by Physical Reads」セクションも参考になります(AWRレポートの読み方参照)。DROP TABLESPACEは対象の表領域が「デフォルトTEMP」に設定されていると実行できません。まず別のTEMP表領域を作成してデフォルトを切り替え(ALTER DATABASE DEFAULT TEMPORARY TABLESPACE)、すべてのユーザーのTEMPも変更してから実行してください。また、DROPはTEMPFILE内に使用中セグメントがない状態でのみ成功します。v$sort_usageでセッションが残っていないか確認してから実行します。まとめ
- 確認:
v$sort_usageでセッション別、v$temp_space_headerで全体のTEMP使用状況を把握する - 即時対処:消費中のセッションを
ALTER SYSTEM KILL SESSION ... IMMEDIATEで強制終了 - サイズ縮小:
ALTER DATABASE TEMPFILE ... RESIZEでファイル縮小(使用中ブロックがある場合はエラー) - 確実な初期化:新TEMP作成→デフォルト変更→旧TEMP削除の順で再作成
- 予防策:
PGA_AGGREGATE_TARGETを増やしてスピルアウトを減らす、SQLチューニングで不要なソートを削除する - ORA-01652:TEMPFILEのリサイズまたは追加で対応し、根本原因のSQL特定も実施

