[Oracle] データファイルを縮小できない!?(ORA-03297エラー) | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

表領域から大きなテーブルやインデックスを削除したり、中身をザックリ削除してから再作成したりすると、当然、使用されていたエクステントが解放されて、表領域および表領域を構成するデータファイルはスカスカになります。

そこで、スカスカになったのでデータファイルのサイズを縮小しようと以下のようなコマンドを実行すると

alter database datafile 
  'C:\oracle\oradata\orcl\user01.dbf' resize 100m;


ORA-03297エラーが発生し、縮小できないことがあります。


データファイルを縮小する場合、縮小可能なのはデータファイルの一番後ろにあるデータより後ろの部分だけです。


要するに末尾の空き領域を切り捨てるだけで、後ろのデータを前に詰めるなどという気の利いたことはやってくれないのです。

例えば 1GB のデータファイルがあったとして、そのうち、100MB 未満しか使用していないとしても、一番後ろのデータが 950MB の位置にあれば 950MB までしか縮小できないということになります。

故に、このような状態のデータファイルを 100MB に縮小しようと上記のようなコマンドを実行すると、以下のようなエラーが発生するというわけです。

ORA-03297: ファイルには、要求したRESIZE値を超える使用中のデータが含まれています。


それでも、何とかして縮小したいという場合には、後ろの方にあるデータを前に持ってくればいいのですが...

そのためにはまず後ろの方には何が入っているのかを調べなくてはなりません。


データファイルの中身(エクステント)について知るにはDBA_EXTENTSを参照します。

select e.owner, e.segment_name, e.segment_type, e.block_id, e.blocks
  from dba_extents e
  inner join dba_data_files f
    on e.file_id = f.file_id
  where file_name = UPPER( 'c:\oracle\oradata\orcl\users01.dbf' )
  order by e.block_id desc


DBA_EXTENTSとDBA_DATA_FILESと引っかけて、データファイル名を条件に絞り込めば、該当データファイルのエクステント一覧を取得することができます。


また、ブロックIDの降順で並べ替えてやることにより、データファイルの後ろの方から前の方へという順番で取得できます。


さらにブロックIDとブロック・サイズを乗算してやればそのエクステントの位置を知ることもできます。

この一覧を元に、該当データファイルの後ろの方にあるセグメント(オブジェクト)をALTER TABLE ~ MOVE ~コマンドやALTER INDEX ~ REBUILDコマンドなどを使って前に持ってくるなり、一時的に別の表領域に退避するなりしたあと、改めてALTER DATABASE DATAFILE ~ RESIZE ~コマンドを実行すれば首尾よく縮小できるはずです。

なお、Oracle Enterprise Managerの[表領域マップの表示]という機能(※)を使えば、表領域内のエクステントの分布をビジュアルで表示することもできます。


ざっくりどんな感じかを確かめたいなら、この方法が楽でいいでしょう。

※Enterprise Editionのみの機能のようです。