株式会社コーソル

KNOWLEDGE

コーソルの技術情報

コーソルでは経験豊かなエンジニアが、Oracle Databaseに関するお役立ち情報を発信しています。
データベースのチューニングや設定にお役立ていただけます。

KNOWLEDGE検索人気のキーワード

Oracle DB ベストプラクティス

表が断片化したときの対処方法 / 表の再編成方法

表には行データが格納されます。システムの運用において行データの更新や削除が数多く実行された結果として、行データの格納状況に偏りができて、意図しない空き領域が発生する状態、いわゆる「断片化」した状態になる場合があります。
断片化に対処するためには、テーブルを再編成する必要があります。
再編成を行う方法にはいくつかありますが、再編成中でのデータへのアクセスが可能なオンライン再編成と、アクセスが不可となるオフライン再編成の2つに大別されます。

01.オフライン再編成

オフライン再編成は、再編成中に表のデータにアクセスできない再編成方法です。

ALTER TABLE MOVEコマンド

異なる表領域または現在表が格納されている表領域に表を移動します。
表を移動すると、当然ながら表に格納されたデータも移動することになり、この処理の過程で「データの詰め直し」に相当する処理が実行され、「断片化」が解消されます。

 

データ退避→truncate tableしてデータ再投入

DataPump expdpコマンド やexpコマンドを使用して、表に格納されたデータをいったん退避した後で、
truncate tableを実行して表に格納されたデータを削除するのと合わせて、表に割り当てられた領域を解放します。
そして、DataPump impdpコマンド やimpコマンドを使用して、退避したデータを再投入します。
データを再投入する過程で、いわば「データの詰め直し」に相当する処理が実行されるため、「断片化」を解消できます。
truncate tableを実行する代わりにdrop table + create tableを使用できますが、テーブルのオブジェクト権限の設定が失われることに注意が必要です。

02.オンライン再編成

オンライン再編成は、再編成中に表のデータにアクセス可能な再編成方法です。
再編成が「データの詰め直し」において実行される点は、オフライン再編成と同様ですが、
オフライン再編成は「データの詰め直し」が全データ一括で実行しますが、
オンライン再編成は「データの詰め直し」を個々のデータをDMLベースで移動することで実行します。
このため、データ量が多くなるにつれて、長い処理時間が必要となる傾向を持ちます。
したがって、データ量が多い場合は、事前に検証を実施することをお勧めします。

ALTER TABLE SHRINK コマンド

Oracle Database 10.1 以降で、表領域のエクステント管理方式に自動セグメント領域管理方式(ASSM)を使用している場合、
ALTER TABLE SHRINK コマンドでオンライン再編成を実行できます。なお、ALTER TABLE SHRINK コマンドを使用するためには、行移動(ROW MOVEMENT)を有効化する必要があります。

表empに対してALTER TABLE SHRINK コマンドを実行した例
SQL> ALTER TABLE emp ENABLE ROW MOVEMENT;
Table altered.
SQL> ALTER TABLE emp shrink space;
Table altered.
オンラインでの表の再定義の活用

Enterprise Editionでのみ使用可能なオンライン再定義機能(DBMS_REDEFINITIONパッケージ)を活用して、ALTER TABLE MOVE相当の処理を実行します。
DBMS_REDEFINITIONパッケージの使用方法は直感的に理解しにくい部分があります。実際に実施される場合は、マニュアルをご確認することをお勧めします。

表empに対してオンライン再定義による再編成を実行した例
SQL> create table INTERIM as select * from EMP WHERE 0 = 1;
Table created.
SQL> exec DBMS_REDEFINITION.CAN_REDEF_TABLE('SCOTT','EMP', DBMS_REDEFINITION.CONS_USE_ROWID);
PL/SQL procedure successfully completed.
SQL> BEGIN
2     DBMS_REDEFINITION.START_REDEF_TABLE(
3                   uname => 'SCOTT',
4                   orig_table => 'EMP',
5                   int_table => 'INTERIM',
6                   options_flag => DBMS_REDEFINITION.CONS_USE_ROWID);
7  END;
8  /
PL/SQL procedure successfully completed.
SQL> DECLARE
2     error_count pls_integer := 0;
3  BEGIN
4     DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS('SCOTT', 'EMP', 'INTERIM', 1, TRUE,TRUE,TRUE,FALSE, error_count);
5     DBMS_OUTPUT.PUT_LINE('errors := ' || TO_CHAR(error_count));
6  END;
7  /
PL/SQL procedure successfully completed.
SQL> exec DBMS_REDEFINITION.SYNC_INTERIM_TABLE('SCOTT', 'EMP', 'INTERIM');
PL/SQL procedure successfully completed.
SQL>exec DBMS_REDEFINITION.FINISH_REDEF_TABLE('SCOTT','EMP','INTERIM');
PL/SQL procedure successfully completed.