【Oracle】ORA-01652の原因と解決方法|unable to extend temp segment・TEMP表領域不足の確認と対処

【Oracle】ORA-01652の原因と解決方法|unable to extend temp segment・TEMP表領域不足の確認と対処 Oracle

ORA-01652: unable to extend temp segment は、Oracleが処理に必要な一時セグメントを拡張できない時に発生するエラーです。よくあるのは、ソート、GROUP BYDISTINCT、ハッシュ結合、インデックス作成、CTAS、Data PumpなどでTEMP表領域を大量に使い、必要な領域を確保できなくなるケースです。

Oracle公式のエラーメッセージでも、処理に追加領域が必要だが表領域サイズを増やせないこと、TEMP表領域では同時利用によって発生することが説明されています。つまり、ORA-01652は「TEMPを足せば終わり」と決めつけず、今誰がTEMPを使っているか、SQLが過剰にTEMPを使っていないか、表領域の上限に達していないかを分けて確認します。

先に結論
ORA-01652が出たら、まずTEMP使用中セッション、TEMP表領域の空き、対象SQL_IDを確認します。緊急対応としてTEMPFILE追加やAUTOEXTEND見直しを行うことはありますが、再発防止ではSQLのソート量、結合方式、並列度、インデックス作成方式、同時実行数を見直します。
スポンサーリンク

ORA-01652とは

ORA-01652は、古い表現では unable to extend temp segment by ... in tablespace ... と表示されることが多いエラーです。新しいメッセージでは、対象セグメント種別、表領域名、SQL ID、セッションが使っているTEMP量などが表示される場合があります。

名前に temp segment とあるためTEMP表領域だけの問題に見えますが、処理内容やバージョンによっては一時セグメントを確保する対象表領域の問題として表れることもあります。まずエラーメッセージに出ている表領域名を確認し、TEMP表領域なのか、通常の表領域なのかを見分けます。表領域全体の考え方は 表領域の記事 も参考になります。

TEMP表領域不足

ソートやハッシュ結合などでTEMPを使い切っている状態です。ORA-01652で最もよく見るパターンです。

同時実行による一時的な逼迫

重いSQLやバッチが同時に動き、TEMPを奪い合っている状態です。時間をずらすだけで回避できることもあります。

表領域の上限到達

AUTOEXTENDがOFF、MAXSIZE到達、ディスク空き不足などで拡張できない状態です。

SQLがTEMPを使いすぎている

不要な全件ソート、巨大なDISTINCT、統計不備による悪い実行計画、過剰な並列実行などが原因になります。

まず確認するSQL

発生中に確認できる場合は、どのセッションがTEMPを使っているかを見ます。V$TEMPSEG_USAGE から、ユーザー、SQL_ID、使用ブロック数、セグメント種別を確認します。

check-tempseg-usage.sql
SELECT
    s.sid,
    s.serial#,
    s.username,
    u.sql_id,
    u.tablespace,
    u.segtype,
    ROUND(u.blocks * ts.block_size / 1024 / 1024) AS used_mb,
    s.module,
    s.program,
    s.machine
FROM v$tempseg_usage u
JOIN v$session s ON s.saddr = u.session_addr
JOIN dba_tablespaces ts ON ts.tablespace_name = u.tablespace
ORDER BY used_mb DESC;

SQL_IDが分かれば、どのSQLがTEMPを使っているかを確認します。

check-sql-text.sql
SELECT sql_id, child_number, executions, elapsed_time, disk_reads, buffer_gets
FROM v$sql
WHERE sql_id = :sql_id;

SELECT sql_text
FROM v$sqltext
WHERE sql_id = :sql_id
ORDER BY piece;

セッション調査の基本は セッション確認の記事 も参考になります。権限がなく V$ 系ビューを見られない場合は、発生時刻、ユーザー、画面名、バッチ名、SQL_ID、エラーメッセージ内の表領域名をDBAへ渡します。

TEMP表領域の空きと上限を確認する

次に、TEMPFILEのサイズ、AUTOEXTEND、MAXSIZEを確認します。空きがないだけでなく、AUTOEXTENDが有効でもMAXSIZEやディスク空きで止まっていることがあります。

check-temp-files.sql
SELECT
    tablespace_name,
    file_name,
    ROUND(bytes / 1024 / 1024) AS size_mb,
    autoextensible,
    ROUND(maxbytes / 1024 / 1024) AS max_mb
FROM dba_temp_files
ORDER BY tablespace_name, file_name;
check-temp-space-header.sql
SELECT
    tablespace_name,
    ROUND(SUM(bytes_used) / 1024 / 1024) AS used_mb,
    ROUND(SUM(bytes_free) / 1024 / 1024) AS free_mb
FROM v$temp_space_header
GROUP BY tablespace_name
ORDER BY tablespace_name;

TEMP表領域の肥大化や使用状況の詳しい見方は TEMP表領域の肥大化防止記事TEMP表領域クリーンアップ記事 も参考になります。

使用率として見たい場合は、使用量と空き容量を合算して割合を出します。監視に使う場合は一瞬のピークだけで判断せず、時間帯、実行中ジョブ、SQL_IDと合わせて見ます。

check-temp-usage-rate.sql
SELECT
    tablespace_name,
    ROUND(SUM(bytes_used) / 1024 / 1024) AS used_mb,
    ROUND(SUM(bytes_free) / 1024 / 1024) AS free_mb,
    ROUND(
        SUM(bytes_used) / NULLIF(SUM(bytes_used + bytes_free), 0) * 100,
        1
    ) AS used_pct
FROM v$temp_space_header
GROUP BY tablespace_name
ORDER BY used_pct DESC;

緊急対応: TEMPFILEを追加する

本番障害で処理を止められない場合、まずTEMPFILE追加やリサイズで逃がすことがあります。ただし、ファイル追加はディスク容量、運用ルール、ASM/ファイルシステム構成を確認してから行います。

add-tempfile.sql
ALTER TABLESPACE temp
ADD TEMPFILE '/u01/app/oracle/oradata/ORCL/temp02.dbf'
SIZE 10G
AUTOEXTEND ON
NEXT 1G
MAXSIZE 30G;
resize-tempfile.sql
ALTER DATABASE TEMPFILE '/u01/app/oracle/oradata/ORCL/temp01.dbf'
RESIZE 20G;
TEMPを増やすだけで終わらせない
TEMPFILE追加は緊急回避として有効ですが、根本原因がSQLの悪い実行計画や過剰な同時実行なら再発します。容量を増やした後に、どのSQLがどれだけTEMPを使ったかを必ず確認します。データファイル追加やリサイズ全般は データファイル追加の記事 も参考になります。

AUTOEXTENDとMAXSIZEを確認する

AUTOEXTENDがOFFなら、ファイルサイズ上限に達した時点で拡張できません。AUTOEXTENDがONでも、MAXSIZEが小さい、ディスクに空きがない、ASMディスクグループが不足している場合はORA-01652になります。

enable-autoextend-tempfile.sql
ALTER DATABASE TEMPFILE '/u01/app/oracle/oradata/ORCL/temp01.dbf'
AUTOEXTEND ON
NEXT 1G
MAXSIZE 30G;

AUTOEXTENDの見方と変更は AUTOEXTENDの記事 に詳しくまとめています。一方で、無制限に伸ばす設定はストレージ枯渇を招くため、監視と上限設計をセットにします。

SQL側でTEMP使用量を減らす

ORA-01652の再発防止では、TEMPを使いすぎるSQLを見直します。TEMPは主にソート、ハッシュ結合、集計、重複排除、インデックス作成、一時表処理で使われます。

ORDER BY

不要な全件ソートをしていないか確認します。画面表示ならページングや必要件数の絞り込みを検討します。

DISTINCT

重複が発生する結合をDISTINCTで隠していないか確認します。結合条件の見直しが先です。

GROUP BY

集計対象を先に絞れるか、不要な列を持ち回っていないか確認します。

HASH JOIN

統計情報が古い、結合順が悪い、PGA不足でTEMPへ退避している可能性があります。

CREATE INDEX

大きなインデックス作成や再構築でTEMPを使います。時間帯、並列度、表領域を確認します。

check-execution-plan.sql
EXPLAIN PLAN FOR
SELECT /* target sql */ *
FROM orders o
JOIN order_details d ON d.order_id = o.order_id
ORDER BY o.order_date DESC;

SELECT *
FROM TABLE(DBMS_XPLAN.DISPLAY);

インデックス作成や再構築時にORA-01652が出る場合は、作成対象、並列度、作業時間帯、TEMP表領域の余裕を見直します。インデックス運用の基本は インデックスの記事 も参考になります。

同時実行数を見直す

単体では成功するSQLでも、同じ時間帯に複数実行されるとTEMPを使い切ることがあります。夜間バッチ、帳票出力、集計SQL、Data Pump、インデックス再構築が重なる時間帯は特に注意します。

時間帯をずらす

重い集計やインデックス作成を同じ時間に集中させないようにします。

並列度を下げる

並列実行は速くなる反面、TEMPやPGAを一気に消費することがあります。

バッチを分割する

全期間を一度に処理せず、月単位やキー範囲で分割します。

キュー化する

同時に走らせず、重い処理を順番に流す仕組みにします。

監視と再発防止

ORA-01652は、発生後にTEMP使用中セッションが消えてしまうと原因を追いにくくなります。再発防止では、TEMP使用率だけでなく、どのSQL_IDがいつTEMPを使ったかを残せるようにします。

警告しきい値

TEMP使用率が70%や80%を超えたら警告するなど、業務時間帯に合わせてしきい値を決めます。

SQL_IDの保存

大量TEMP使用セッションのSQL_ID、ユーザー、module、program、machineを監視ログへ残します。

ジョブとの突き合わせ

夜間バッチ、帳票、Data Pump、インデックス再構築の実行時間とTEMP使用ピークを突き合わせます。

増加傾向の確認

データ量増加で毎月TEMP使用量が増えている場合は、容量追加だけでなくSQLや処理方式を見直します。

monitor-heavy-temp-users.sql
SELECT
    SYSDATE AS checked_at,
    s.username,
    s.sid,
    s.serial#,
    u.sql_id,
    u.tablespace,
    u.segtype,
    ROUND(u.blocks * ts.block_size / 1024 / 1024) AS used_mb,
    s.module,
    s.program,
    s.machine
FROM v$tempseg_usage u
JOIN v$session s ON s.saddr = u.session_addr
JOIN dba_tablespaces ts ON ts.tablespace_name = u.tablespace
WHERE u.blocks * ts.block_size >= 1024 * 1024 * 1024
ORDER BY used_mb DESC;

上の例では1GB以上TEMPを使っているセッションを抽出しています。実際のしきい値は、TEMP表領域サイズ、通常時のピーク、業務影響に合わせて調整してください。

セッションを止める前に確認する

ORA-01652発生時、TEMPを大量に使っているセッションを止めたくなることがあります。ただし、業務処理やバッチを強制終了すると、ロールバックや再実行、外部連携の確認が必要になることがあります。

止める前に、処理名、利用者、SQL_ID、実行時間、更新処理か参照処理かを確認します。セッションの確認や停止手順は セッション確認の記事 を参照してください。

似た容量不足エラーとの違い

ORA-01652はTEMPや一時セグメントの拡張失敗として出ることが多いですが、容量不足系のエラーは他にもあります。エラー番号と対象表領域を見て切り分けます。

ORA-01652

一時セグメントを拡張できません。ソート、集計、ハッシュ結合、インデックス作成などでTEMPを大量に使う時に発生しやすいです。

ORA-01653

表を拡張できないエラーです。通常の表領域で表セグメントを拡張できない時に出ます。

ORA-01654

インデックスを拡張できないエラーです。インデックス表領域やAUTOEXTENDを確認します。

ORA-30036

UNDO表領域を拡張できないエラーです。長いトランザクションやUNDO_RETENTIONを確認します。

容量不足全般

緊急対応の流れは 容量不足の緊急対応記事 も参考になります。

対応手順まとめ

  1. エラーメッセージの表領域名とSQL_IDを確認する
  2. V$TEMPSEG_USAGE でTEMP使用中セッションを確認する
  3. DBA_TEMP_FILESV$TEMP_SPACE_HEADER でサイズ、空き、AUTOEXTENDを確認する
  4. 緊急時はTEMPFILE追加、リサイズ、AUTOEXTEND見直しを検討する
  5. 同時実行中の重いSQLやバッチを確認する
  6. 対象SQLの実行計画を確認し、ソート、集計、DISTINCT、HASH JOINを見直す
  7. インデックス作成や再構築なら、並列度と時間帯を見直す
  8. 監視と再発防止としてTEMP使用量の定期確認を入れる

ORA-01652は、緊急対応としてはTEMP表領域を増やす判断になりやすいエラーです。ただし、TEMPを増やすだけでは、重いSQLや同時実行が増えた時に再発します。発生時にSQL_IDとTEMP使用量を残し、どの処理がどれだけ使ったかを後から追えるようにしておくことが大切です。

よくある質問

ORA-01652はTEMP表領域を増やせば解決ですか?

一時的には解決することがあります。ただし、SQLが過剰にTEMPを使っている場合や同時実行が原因の場合は再発します。TEMP使用中セッションとSQL_IDを確認してください。

単体では成功するSQLが本番だけ失敗します

本番では同時実行、データ量、統計情報、並列度が違うことがあります。同じSQLでも、他の処理と重なるとTEMP不足になることがあります。

TEMPFILEを削除すれば空きますか?

使用中のTEMPFILEを安易に削除してはいけません。TEMP表領域の再作成やTEMPFILE整理は、利用状況と運用手順を確認してから行います。

ORA-01652のSQLを特定できません

発生中なら V$TEMPSEG_USAGE でSQL_IDを確認します。発生後に消えている場合は、アプリログ、監視ログ、AWR/ASH、ジョブログから発生時刻と処理名を追います。

参考