【Oracle】TEMP 表領域の肥大化を防ぐ方法|原因特定・使用状況監視・TEMPFILE 再作成・PGA チューニングまで解説

【Oracle】TEMP 表領域の肥大化を防ぐ方法|原因特定・使用状況監視・TEMPFILE 再作成・PGA チューニングまで解説 Oracle

TEMP 表領域は ORDER BY / GROUP BY / DISTINCT / ハッシュ結合などのソートやハッシュ処理で一時的に使用される作業領域です。PGA(メモリ)に収まらない処理が TEMP に書き出されるため、大量データの処理でTEMP が肥大化し、ディスクを圧迫することがあります。

本記事では、肥大化の原因特定犯人セッションの検出TEMPFILE の縮小・再作成PGA チューニングによる根本対策まで解説します。

この記事でわかること
・TEMP 表領域が肥大化する 5 つの原因
・V$SORT_USAGE で TEMP を大量消費しているセッション(犯人)を特定
・DBA_TEMP_FREE_SPACE で使用状況を監視
・TEMPFILE の縮小(RESIZE)と再作成
・PGA_AGGREGATE_TARGET のチューニング(根本対策)
・TEMP 表領域グループの活用
・ORA-01652 の緊急対処
スポンサーリンク

TEMP 表領域が肥大化する原因

原因 発生する SQL 対策
大量データのソート ORDER BY / GROUP BY(PGA 不足でディスクソート) PGA_AGGREGATE_TARGET を拡大 / インデックスで ORDER BY を代替
ハッシュ結合 大テーブル同士の JOIN(ハッシュテーブルが PGA に収まらない) PGA を拡大 / 結合対象のデータ量を WHERE で削減
DISTINCT / UNION 重複排除のためのソート UNION ALL で代替可能か検討 / EXISTS で書き換え
グローバルテンポラリテーブル INSERT INTO gtt SELECT … の大量データ GTT のサイズを見直し / 処理後に TRUNCATE
未クローズのカーソル / セッション 長時間実行中の SQL がTEMP を占有し続ける 犯人セッションを特定して KILL
TEMP が大きいこと自体は異常ではない
大量データの ORDER BY やハッシュ結合を行えば TEMP の使用は正常な動作です。問題なのは「処理が終わっても TEMP が解放されない」「想定以上に TEMP を使う SQL がある」ケースです。まず犯人を特定し、SQL チューニングか PGA 拡大で対処します。

TEMP の使用状況を確認する

DBA_TEMP_FREE_SPACE(全体の使用状況)

SQL(TEMP 表領域の使用率)
-- TEMP 表領域の全体使用状況
SELECT tablespace_name,
       ROUND(tablespace_size/1024/1024) AS total_mb,
       ROUND(allocated_space/1024/1024) AS allocated_mb,
       ROUND(free_space/1024/1024) AS free_mb,
       ROUND(allocated_space/tablespace_size * 100, 1) AS used_pct
FROM dba_temp_free_space;

V$SORT_USAGE(セッション別の TEMP 使用量)

SQL(TEMP を大量消費しているセッションを特定: 犯人捜し)
-- セッション別の TEMP 使用量(降順: 最も使っているセッションが先頭)
SELECT s.sid, s.serial#, s.username, s.program,
       s.sql_id,
       ROUND(t.blocks * 8192/1024/1024, 1) AS temp_mb,
       SUBSTR(q.sql_text, 1, 80) AS sql_text
FROM v$sort_usage t
JOIN v$session s ON t.session_addr = s.saddr
LEFT JOIN v$sql q ON s.sql_id = q.sql_id
ORDER BY t.blocks DESC;
SQL(TEMP 使用量のユーザー別集計)
-- ユーザー別の TEMP 消費量合計
SELECT s.username,
       COUNT(*) AS session_count,
       ROUND(SUM(t.blocks * 8192)/1024/1024, 1) AS total_temp_mb
FROM v$sort_usage t
JOIN v$session s ON t.session_addr = s.saddr
GROUP BY s.username
ORDER BY total_temp_mb DESC;
SQL(V$TEMPSEG_USAGE: V$SORT_USAGE の別名)
-- V$TEMPSEG_USAGE = V$SORT_USAGE の別名(同じ内容)
SELECT username, segtype,
       ROUND(SUM(blocks * 8192)/1024/1024, 1) AS temp_mb
FROM v$tempseg_usage
GROUP BY username, segtype
ORDER BY temp_mb DESC;

-- segtype: SORT / HASH / DATA / INDEX / LOB_DATA 等
-- SORT = ORDER BY, HASH = ハッシュ結合
segtype でどの処理が TEMP を使っているかわかる
SORT: ORDER BY / GROUP BY / DISTINCT でのソート
HASH: ハッシュ結合(大テーブル JOIN)
DATA: CTAS / INSERT SELECT の一時データ
segtype が SORT なら PGA 拡大やインデックス追加、HASH ならデータ量の削減が有効です。

TEMP を大量消費しているセッションを KILL する

SQL(犯人セッションの特定と KILL)
-- (1) 犯人を特定
SELECT s.sid, s.serial#, s.username,
       ROUND(t.blocks * 8192/1024/1024, 1) AS temp_mb,
       s.sql_id
FROM v$sort_usage t
JOIN v$session s ON t.session_addr = s.saddr
ORDER BY t.blocks DESC
FETCH FIRST 5 ROWS ONLY;

-- (2) KILL(SID と SERIAL# を指定)
ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;

-- KILL 後に TEMP が解放されるまで数秒〜数分かかる場合がある
KILL する前に SQL の内容を確認
闇雲に KILL すると業務に影響します。sql_id から SQL の内容を確認し、不要な SQL(テスト中 / 放置されたセッション等)であることを確認してから KILL してください。業務上必要な SQL なら、完了を待つか PGA チューニングで対処します。

TEMPFILE の縮小と再作成

TEMP 表領域が肥大化した後、TEMPFILE は自動的には縮小しません。手動で RESIZE するか、TEMPFILE を再作成する必要があります。

TEMPFILE のリサイズ(縮小)

SQL(TEMPFILE の縮小)
-- 現在の TEMPFILE サイズを確認
SELECT file_name, ROUND(bytes/1024/1024) AS size_mb, autoextensible
FROM dba_temp_files;

-- RESIZE で縮小(使用中でないブロック分だけ縮小可能)
ALTER DATABASE TEMPFILE '/oracle/oradata/ORCL/temp01.dbf' RESIZE 500M;

-- ORA-03297 が出る場合: まだ使用中のブロックがある
-- → 全セッションの TEMP 使用が解放されるまで待つか、DB 再起動

TEMPFILE の DROP + 再作成(確実な方法)

SQL(TEMPFILE の再作成)
-- (1) 既存の TEMPFILE を DROP
ALTER TABLESPACE temp DROP TEMPFILE '/oracle/oradata/ORCL/temp01.dbf';

-- (2) 新しい TEMPFILE を追加(適切なサイズで)
ALTER TABLESPACE temp ADD TEMPFILE '/oracle/oradata/ORCL/temp01.dbf'
    SIZE 1G AUTOEXTEND ON NEXT 100M MAXSIZE 5G;

-- ※ TEMP 表領域に TEMPFILE が 1 つしかない場合は DROP できない
-- → 先に別の TEMPFILE を追加してから DROP

TEMP 表領域自体を再作成(最も確実)

SQL(TEMP 表領域の再作成)
-- (1) 新しい TEMP 表領域を作成
CREATE TEMPORARY TABLESPACE temp_new
    TEMPFILE '/oracle/oradata/ORCL/temp_new01.dbf'
    SIZE 1G AUTOEXTEND ON NEXT 100M MAXSIZE 5G;

-- (2) DB のデフォルト一時表領域を変更
ALTER DATABASE DEFAULT TEMPORARY TABLESPACE temp_new;

-- (3) 全ユーザーの一時表領域を変更(任意)
-- ALTER USER app_user TEMPORARY TABLESPACE temp_new;

-- (4) 旧 TEMP 表領域を DROP(使用中のセッションがなくなってから)
DROP TABLESPACE temp INCLUDING CONTENTS AND DATAFILES;
TEMP 表領域の再作成は全セッションが旧 TEMP を使い終わってから
旧 TEMP を使用中のセッションがある間は DROP できません。デフォルト TEMP を新しい表領域に変更した後、全セッションが切断されるのを待つか、業務時間外に実施してください。

PGA チューニング(根本対策)

TEMP の使用はPGA(メモリ上の作業領域)に収まらない処理が発生した結果です。PGA を拡大すればメモリ内で処理が完了し、TEMP への書き出し(ディスクソート)が減少します。

SQL(PGA の現在設定と使用状況)
-- PGA_AGGREGATE_TARGET の確認
SHOW PARAMETER pga_aggregate_target;

-- PGA の使用状況
SELECT name, ROUND(value/1024/1024) AS mb
FROM v$pgastat
WHERE name IN (
    'aggregate PGA target parameter',
    'aggregate PGA auto target',
    'total PGA allocated',
    'maximum PGA allocated',
    'cache hit percentage'
);

-- cache hit percentage: 100% に近いほどメモリ内で処理完了
-- 低い場合(80% 以下)は PGA の拡大を検討
SQL(PGA の拡大)
-- PGA_AGGREGATE_TARGET を 2GB に拡大
ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=BOTH;

-- 個別セッションの作業領域サイズ上限を確認
SHOW PARAMETER workarea_size_policy;  -- AUTO(デフォルト推奨)
PGA パラメータ 意味 推奨
PGA_AGGREGATE_TARGET PGA 全体の目標サイズ SGA の 20%〜50% 程度。大量ソートが多い場合は増加
WORKAREA_SIZE_POLICY AUTO / MANUAL AUTO(Oracle が自動調整)
PGA を拡大すると TEMP の使用が劇的に減る
PGA cache hit percentage が 80% 以下の場合、多くのソートがディスク(TEMP)に書き出されています。PGA_AGGREGATE_TARGET を拡大すればメモリ内処理の割合が増え、TEMP の消費が大幅に削減されます。

SQL チューニングで TEMP 使用を削減する

原因 SQL パターン チューニング方法
ORDER BY で全件ソート インデックスで ORDER BY を代替。FETCH FIRST N ROWS ONLY で件数制限
大テーブル同士の JOIN WHERE 条件でデータ量を絞ってから JOIN。インデックスの追加
DISTINCT で重複排除 EXISTS / IN で書き換え可能か検討。重複の原因を JOIN で修正
UNION(重複排除あり) UNION ALL で代替可能か検討(重複排除不要なら ALL が高速)
GROUP BY + HAVING WHERE で先にフィルタしてから GROUP BY(集計対象を削減)

TEMP 表領域グループ(負荷分散)

TEMP 表領域グループを使うと、複数の TEMP 表領域を束ねてソート処理を分散できます。大規模なパラレル処理で TEMP がボトルネックになる場合に有効です。

SQL(TEMP 表領域グループ)
-- グループに属する TEMP 表領域を作成
CREATE TEMPORARY TABLESPACE temp1
    TEMPFILE '/oracle/disk1/temp1.dbf' SIZE 2G
    TABLESPACE GROUP temp_group;

CREATE TEMPORARY TABLESPACE temp2
    TEMPFILE '/oracle/disk2/temp2.dbf' SIZE 2G
    TABLESPACE GROUP temp_group;

-- ユーザーにグループを割り当て
ALTER USER app_user TEMPORARY TABLESPACE temp_group;

-- グループの確認
SELECT * FROM dba_tablespace_groups;

ORA-01652 の緊急対処

エラーメッセージ
ORA-01652: unable to extend temp segment by 128 in tablespace TEMP
対処 SQL 効果
TEMPFILE を追加 ALTER TABLESPACE temp ADD TEMPFILE ‘…’ SIZE 2G AUTOEXTEND ON 即効
既存 TEMPFILE を拡大 ALTER DATABASE TEMPFILE ‘…’ RESIZE 5G 即効
犯人セッションを KILL ALTER SYSTEM KILL SESSION ‘sid,serial#’ 即効
PGA を拡大 ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=BOTH 中長期
SQL をチューニング 不要なソートを排除 / データ量を削減 根本対策

実務パターン集

パターン(1): TEMP を大量消費している犯人を特定して対処

SQL
-- (1) 犯人を特定
SELECT s.sid, s.serial#, s.username,
       ROUND(SUM(t.blocks)*8192/1024/1024, 1) AS temp_mb,
       s.sql_id
FROM v$sort_usage t
JOIN v$session s ON t.session_addr = s.saddr
GROUP BY s.sid, s.serial#, s.username, s.sql_id
ORDER BY temp_mb DESC;

-- (2) SQL の内容を確認
SELECT sql_fulltext FROM v$sql WHERE sql_id = 'abc123def456';

-- (3) 不要なセッションなら KILL
-- ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE;

パターン(2): 肥大化した TEMP を縮小

SQL
-- (1) 現在のサイズを確認
SELECT file_name, ROUND(bytes/1024/1024) AS size_mb FROM dba_temp_files;

-- (2) 使用中のセッションがないか確認
SELECT COUNT(*) FROM v$sort_usage;

-- (3) 0 件なら RESIZE で縮小
ALTER DATABASE TEMPFILE '/oracle/oradata/ORCL/temp01.dbf' RESIZE 1G;

パターン(3): PGA cache hit percentage の改善

SQL
-- (1) 現在の cache hit percentage を確認
SELECT name, value FROM v$pgastat WHERE name = 'cache hit percentage';
-- 80% 以下 = ディスクソートが多い

-- (2) PGA を拡大
ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=BOTH;

-- (3) しばらく運用して cache hit percentage が改善したか確認

パターン(4): 定期監視スクリプト

SQL(TEMP 使用率が 80% 超でアラート)
-- TEMP 使用率の監視
SELECT tablespace_name,
       ROUND(allocated_space/tablespace_size * 100, 1) AS used_pct
FROM dba_temp_free_space
WHERE allocated_space/tablespace_size * 100 >= 80;
-- 結果があればアラート(メール通知等に組み込む)

よくある質問

QTEMP 表領域は自動的に縮小しますか?
A縮小しません。AUTOEXTEND ON で拡張された TEMPFILE は、処理完了後も大きいままです。手動で RESIZE するか、TEMPFILE を DROP + 再作成してください。
QDB を再起動すれば TEMP は縮小しますか?
ADB 再起動で TEMP の使用中データは解放されますが、TEMPFILE 自体のサイズは変わりません。ファイルサイズを縮小するには RESIZE または再作成が必要です。
QV$SORT_USAGE が 0 件なのに TEMP が大きいままです
AV$SORT_USAGE は現在使用中のセッションのみ表示します。過去の処理で TEMPFILE が拡張されたまま残っているだけです。RESIZE または TEMPFILE 再作成で縮小してください。
QTEMP 表領域の AUTOEXTEND は ON にすべきですか?
AON にすることを推奨します。AUTOEXTEND OFF だと大量ソート時に ORA-01652 が発生します。ただし MAXSIZE を設定して無制限拡張を防いでください。
QTEMP 表領域をバックアップする必要がありますか?
A不要です。TEMP 表領域は一時データのみを格納するため、RMAN / Data Pump のバックアップ対象外です。破損した場合は TEMPFILE を DROP + 再作成するだけで復旧できます。
QPGA_AGGREGATE_TARGET をいくつに設定すべきですか?
A一般的には SGA の 20%〜50% が目安です。V$PGASTAT の cache hit percentage が 80% 以下なら拡大を検討してください。大量のソートやハッシュ結合を行う環境では SGA と同等以上に設定することもあります。

まとめ

TEMP 表領域の管理の要点をまとめます。

やりたいこと 方法
TEMP の使用状況を確認 SELECT * FROM dba_temp_free_space
TEMP を大量消費しているセッションを特定 V$SORT_USAGE + V$SESSION を JOIN して blocks DESC
犯人セッションを KILL ALTER SYSTEM KILL SESSION ‘sid,serial#’ IMMEDIATE
TEMPFILE を縮小 ALTER DATABASE TEMPFILE ‘…’ RESIZE 1G
TEMPFILE を再作成 DROP TEMPFILE → ADD TEMPFILE
TEMP 表領域自体を再作成 CREATE TEMPORARY TABLESPACE → ALTER DATABASE DEFAULT → DROP 旧
根本対策: PGA を拡大 ALTER SYSTEM SET pga_aggregate_target = 2G SCOPE=BOTH
ORA-01652 の緊急対処 ADD TEMPFILE / RESIZE / KILL SESSION

表領域の使用状況確認は「表領域の使用状況を確認する SQL まとめ」、データファイルの追加は「データファイルを追加・変更する方法」、表領域の管理全般は「表領域(Tablespace)完全ガイド」も併せて参照してください。