17 LONGからLOBへの表列の移行

LONGデータ型を使用する表からLOBデータ型へと移行する手法があります。

内容は次のとおりです。

17.1 LONG列からLOB列に移行するメリット

表列をLONGデータ型からLOBデータ型に移行すると、次のようなメリットがあります。

ノート:

様々な手法を使用して、次のいずれかを行うことができます。

  • LONG型の列からCLOB列またはNCLOB列への変換

  • LONG RAW型の列からBLOB型の列への変換

特に明記しないかぎり、この章のLONGからLOBへの変換に関する説明は、これら2つのデータ型変換に適用されます。

様々なアプリケーション開発の使用例におけるLONGデータ型とLOBデータ型のセマンティクスには、次のような違いがあります。

  • LONG型の列の数には制限があります。特定の表に含めることができるLONG型の列は1つのみです。表に含めるLOB型の列の数には制限がありません。

17.2 LONG列からLOB列に移行するための事前条件

LONG列をLOB列に変換する前に、様々な事前条件を満たす必要があります。

関連項目:

表を変換する前にLOB列の制限がLOBへの変換の妨げとなるかどうかを判断するには、LONGからLOBへのアプリケーションの移行を参照してください。

17.2.1 LOBへの変換前のLONG列のドメイン索引削除

LONG列のドメイン索引は、LONG列をLOB列に変換する前に削除する必要があります。

17.2.2 LOBデータ型に変換する表のREDO領域の生成防止

LONG列の変換処理中にREDO領域が生成されると、パフォーマンスが低下することがあります。変換処理中の表に対するREDOがログに記録されるのは、表にLOGGINGが指定されている場合のみです。

また、LONGからLOBへ変換中の列に対するREDOがログに記録されるのは、LOB列の記憶特性がLOGGINGに指定されている場合のみです。LOB列のロギング設定(LOGGINGまたはNOLOGGING)は、LOBが作成された表領域から継承されます。

移行中のREDO領域の生成を回避するには、表を移行する前に次の手順に従います(構文はBNFです)。

  1. 次の文を実行します。ALTER TABLE Long_tab NOLOGGING;
  2. 次の文を実行します。ALTER TABLE Long_tab MODIFY (long_col CLOB [DEFAULT <default_val>]) LOB (long_col) STORE AS (NOCACHE NOLOGGING);

    STORE AS句にNOLOGGINGを指定する場合は、NOCACHEも指定する必要があることに注意してください。

  3. 次の文を実行します。ALTER TABLE Long_tab MODIFY LOB (long_col) (CACHE);
  4. 次の文を実行します。ALTER TABLE Long_tab LOGGING;
  5. 表およびLOB列を含む表領域のバックアップを作成します。

17.3 utldtree.sqlを使用したアプリケーションの最適化方法の判断

表をLONGからLOB列型に移行する場合、PL/SQLでは、アプリケーションの特定の部分の再作成が必要な場合があります。これがどの部分であるかは、rdbms/admin/utldtree.sqlユーティリティを使用して判断できます。

utldtree.sqlユーティリティを使用すると、指定のオブジェクトに依存するすべてのオブジェクトを再帰的に参照できます。たとえば、LONG列を含む表に依存するオブジェクトをすべて参照できます。参照できるのは、権限があるオブジェクトのみです。

utldtree.sqlの使用方法は、utldtree.sqlファイル内に記載されています。また、utldtree.sqlが必要となるのはPL/SQLの場合のみです。SQLおよびOCIの場合は、アプリケーションを変更する必要はありません。

17.4 LONGデータ型からLOBデータ型への表の変換

既存の表をLONGデータ型からLOBデータ型へ移行する場合、様々な問題と方法があります。

内容は次のとおりです。

17.4.1 移行時の問題

移行については、次の一般的な問題があります。

  • 以前のLONG列に対するすべての制約は、新しいLOB列においても保持されます。LONG列で有効な制約は、NULLおよびNOT NULLのみです。これらの列に対する制約、またはこの表の他の列やプロパティを変更するには、移行後にALTER TABLE文を使用します。

  • デフォルト値を指定しない場合、LONG列のデフォルト値がLOB列のデフォルト値となります。

  • 表に対するほとんどの既存のトリガーは引き続き使用できますが、UPDATE OFトリガーで問題が発生する可能性があります。

17.4.2 ALTER TABLEを使用したLONG列からLOB列への変換

SQLのALTER TABLE文を使用すると、LONG列からLOB列に変換できます。

そのためには、次の構文を使用します。

ALTER TABLE [<schema>.]<table_name>
   MODIFY ( <long_column_name> { CLOB | BLOB | NCLOB } 
  [DEFAULT <default_value>]) [LOB_storage_clause];

たとえば、次のように作成された表があるとします。

CREATE TABLE Long_tab (id NUMBER, long_col LONG);

この例では、次のALTER TABLE文を使用して、Long_tab表のlong_col列をCLOBデータ型に変更できます。

ALTER TABLE Long_tab MODIFY ( long_col CLOB );

ノート:

ALTER TABLE文は、表の内容を新しい領域にコピーし、操作の終了時に古い領域を解放します。このため、必要な領域が一時的に2倍になります。

ALTER TABLE文を使用してLONG列をLOB列に変換する場合、次のオプションのみが許可されていることに注意してください。

  • DEFAULT: LOB列のデフォルト値を指定できます。

  • LOB_storage_clause: 変換する列のLOB記憶特性を指定できます。このオプションはMODIFY句に指定できます。

LONG列をLOB型の列に変換する場合、ALTER TABLE文の他のオプションは使用できません。

17.4.3 TO_LOB演算子を使用したLONGからLOB列へのコピー

ALTER TABLEを使用しない場合は、LONG列に対してTO_LOB演算子を使用し、LONG列をLOB列にコピーできます。CREATE TABLE AS SELECT文またはINSERT AS SELECT文でTO_LOB演算子を使用すると、LONG列からCLOB列またはNCLOB列に、またはLONG RAW列からBLOB列にデータをコピーできます。たとえば、LONG列を含む表が次のように作成されているとします。

CREATE TABLE Long_tab (id NUMBER, long_col LONG);  

次の文を使用すると、列をLOB列にコピーできます。

CREATE TABLE Lob_tab (id NUMBER, clob_col CLOB);  
INSERT INTO Lob_tab SELECT id, TO_LOB(long_col) FROM long_tab;  
COMMIT;

INSERTがエラーを戻す場合は(UNDO用の領域がなかった場合)、WHERE句を使用してLONGデータを少しずつLOB列に移行できます。データが正確にコピーされていることを確認した後、元の表を削除し、次のどちらかの手順を使用して新しい表のビューまたはシノニムを作成できます。

DROP TABLE Long_tab;  
CREATE VIEW Long_tab (id, long_col) AS SELECT * from Lob_tab; 

または

DROP TABLE Long_tab;  
CREATE SYNONYM Long_tab FOR Lob_tab;

この一連の操作は、Long_tab表のLong_col列のデータ型をLONGからCLOBに変更する操作と同じです。この方法を使用する場合は、新しい表の制約、トリガー、権限付与および索引を再作成する必要があります。

TO_LOB演算子の使用には、次のような制限事項があることに注意してください。

  • TO_LOBを使用してデータをLOB列にコピーできますが、オブジェクト型のLOB属性にはコピーできません。

  • TO_LOBはリモート表に使用できません。たとえば、次の文は機能しません。

    INSERT INTO tb1@dblink (lob_col) SELECT TO_LOB(long_col) FROM tb2; 
    INSERT INTO tb1 (lob_col) SELECT TO_LOB(long_col) FROM tb2@dblink; 
    CREATE TABLE tb1 AS SELECT TO_LOB(long_col) FROM tb2@dblink; 
    
  • 索引構成表の作成時に、CREATE TABLE AS SELECT文でTO_LOB演算子を使用して、LONGまたはLONG RAW列をLOB列に変換することはできません。

    この制限事項を回避するには、索引構成表を作成してから、TO_LOB演算子を使用してLONG列またはLONG RAW列のINSERT AS SELECTを実行します。

  • どのPL/SQLブロックの中でもTO_LOBを使用できません。

17.4.4 LONG列を含む表のオンライン再定義

LONG列およびLONG RAW列を含む表は、表のオンライン再定義を使用して移行できます。この方法は、高可用性が重要なデータベース表のLONG列を移行する場合に適しています。

この方法を使用するには、次のように、再定義処理中にLONG列をLOB型に変換する必要があります。

  • LONG列をCLOB列またはNCLOB列に変換します。

  • LONG RAW列をBLOB列に変換します。

この変換を実行するには、DBMS_REDEFINITION.START_REDEF_TABLE()プロシージャの列マッピングにTO_LOB()演算子を使用します。

ノート:

LONG列またはLONG RAW列を含む表のオンライン再定義を実行するには、この項で説明するように各列をLOB型に変換する必要があります。

次のリストに、オンライン再定義処理に関係する一般タスクを示します。LONG列とLONG RAW列の変換に固有の問題については、該当する箇所で説明します。ここで説明しないオンライン再定義処理の詳細は、この項の最後に示す関連マニュアルを参照してください。

  • 空の仮表を作成します。再定義処理が完了すると、この表には移行済のデータが保持されます。この仮表で次の操作を行います。

    • 移行元の表にあるLONG列ごとにCLOB列またはNCLOB列を定義します。

    • 移行元の表にあるLONG RAW列ごとにBLOB列を定義します。

  • 再定義プロセスを開始します。そのためには、次のように、DBMS_REDEFINITION.START_REDEF_TABLEをコールし、TO_LOB演算子を使用して列マッピングを渡します。

    DBMS_REDEFINITION.START_REDEF_TABLE(
        'schema_name', 
        'original_table',
        'interim_table', 
        'TO_LOB(long_col_name) lob_col_name',
        'options_flag',
        'orderby_cols'); 
    

    long_col_nameは元の表で変換するLONG列またはLONG RAW列の名前で、lob_col_nameは仮表のLOB列の名前です。このLOB列に変換後のデータが保持されます。

  • DBMS_REDEFINITION.COPY_TABLE_DEPENDENTSプロシージャをコールします。詳細は、関連マニュアルを参照してください。

  • DBMS_REDEFINITION.FINISH_REDEF_TABLEプロシージャをコールします。詳細は、関連マニュアルを参照してください。

パラレル・オンライン再定義

パラレル実行に十分なリソースがあるシステムでは、LONG列のLOB列への再定義は、次の条件下でパラレルに実行できます。

挿入先の表がパーティション化されていない場合:

  • 挿入先の表にLOB列を格納するために使用されるセグメントが、自動セグメント領域管理(ASSM)が使用可能になっている(現在のデフォルト)ローカル管理表領域に属している。

  • 1つのLONG列から1つのLOB列への単純なマッピングが存在し、挿入先の表には1つのLOB列のみがある。

挿入先の表がパーティション化されている場合、パーティション化に通常使用されるパラレル実行方法が適用されます。挿入先の表がパーティション化されている場合、オンライン再定義がパラレルに実行されます。

オンライン再定義の例

次の例に、LOB列を使用したオンライン再定義を示します。

REM Grant privileges required for online redefinition.
GRANT execute ON DBMS_REDEFINITION TO pm;
GRANT ALTER ANY TABLE TO pm;
GRANT DROP ANY TABLE TO pm;
GRANT LOCK ANY TABLE TO pm;
GRANT CREATE ANY TABLE TO pm;
GRANT SELECT ANY TABLE TO pm;

REM Privileges required to perform cloning of dependent objects.
GRANT CREATE ANY TRIGGER TO pm;
GRANT CREATE ANY INDEX TO pm;

connect pm/passwd

drop table cust;
create table cust(c_id   number primary key,
                  c_zip  number,
                  c_name varchar(30) default null,
                  c_long long
                  );
insert into cust values(1, 94065, 'hhh', 'ttt');

-- Creating Interim Table 
-- There is no requirement to specify constraints because they are 
-- copied over from the original table.
create table cust_int(c_id   number not null,
                  c_zip  number,
                  c_name varchar(30) default null,
                  c_long clob
                  );

declare
 col_mapping varchar2(1000);
BEGIN
--  map all the columns in the interim table to the original table
 col_mapping :=
               'c_id             c_id  , '||
               'c_zip            c_zip , '||
               'c_name           c_name, '||
               'to_lob(c_long)   c_long';

dbms_redefinition.start_redef_table('pm', 'cust', 'cust_int', col_mapping);
END;
/

declare
 error_count pls_integer := 0;
BEGIN
  dbms_redefinition.copy_table_dependents('pm', 'cust', 'cust_int',
                                          1, true, true, true, false,
                                          error_count);

  dbms_output.put_line('errors := ' || to_char(error_count));
END;
/

exec  dbms_redefinition.finish_redef_table('pm', 'cust', 'cust_int');

-- Drop the interim table
drop table cust_int;

desc cust;

-- The following insert statement fails. This illustrates 
-- that the primary key constraint on the c_id column is 
-- preserved after migration. 

insert into cust values(1, 94065, 'hhh', 'ttt');

select * from cust;

ノート:

再定義プロセスの詳細は、関連ドキュメントを参照してください。

17.4.5 Oracle Data Pumpを使用したデータベースの移行

新規データベースへの移行の一環としてデータをエクスポートする場合は、移行先データベースにLOB列を持つ表を作成し、データ・ポンプによりLONG-to-LOBファンクションを暗黙的にコールします。

関連項目:

Oracle Data Pumpの詳細は、Oracle Databaseユーティリティを参照してください

17.5 LONGからLOBへのアプリケーションの移行

LONGデータ型とLOBデータ型には、アプリケーションの移行計画に影響したり、アプリケーションの変更を必要とする違いがあります。

17.5.1 LONGからLOBへのアプリケーションの移行について

PL/SQL環境とOCI環境でLONGデータ型に使用するほとんどのAPIは、LOBデータ型にも使用できるように拡張されています。

これらのAPIをまとめて、永続LOB用のデータ・インタフェースまたは単にデータ・インタフェースと呼びます。データ・インタフェースには、特に次のようなメリットがあります。

  • LONGデータ型からLOBデータ型に変換された列を含む表を使用するPL/SQLおよびOCIアプリケーションでは、アプリケーションの変更が最小限ですみます。

  • LOBロケータを扱わずにアプリケーションでLOBデータ型を使用できます。

    関連項目:

17.5.2 クラスタ化表で使用できないLOB列

クラスタ化表には、LOB列は作成できませんが、LONGは作成できます。表がクラスタの一部である場合、LONG列またはLONG RAW列はLOB列に変更できません。

17.5.3 AFTER UPDATE OFトリガーに使用できないLOB列

AFTER UPDATE OFトリガーのUPDATE OFリストには、LOB列を作成できません。LONG列は、この種のトリガーに作成できます。たとえば、次のCREATE TRIGGER文は無効です。

CREATE TABLE t(lobcol CLOB);
CREATE TRIGGER trig AFTER UPDATE OF lobcol ON t ...;

他のすべてのトリガーはLOB列で機能します。

17.5.4 LONGデータ型からLOBデータ型に変換された列の索引の再作成

移行する表の列の索引は、LONG列をLOB列に変換した後に手動で再作成する必要があります。これには、ファンクション索引が含まれます。

LONG列のファンクション索引は、変換処理中は使用できなくなり、変換後に再作成する必要があります。ファンクション索引を使用するアプリケーション・コードは、変換後もそのまま動作します。

LONG列のドメイン索引は、LONG列をLOB列に変換する前に削除する必要があることに注意してください。変換後にドメイン索引を再作成できます。

変換後に索引を再作成するステップは、次のとおりです。

  1. 次のように、元の表から索引を選択します。
    SELECT index_name FROM user_indexes WHERE table_name='LONG_TAB'; 
    

    ノート:

    この問合せでは、表名を大文字で指定する必要があります。

  2. 選択した索引に対して次のコマンドを使用します。
    ALTER INDEX <index> REBUILD

17.5.5 空のLOBとNULLまたは長さが0(ゼロ)のLONGの違い

LOB列には、のLOBを保持できます。空のLOBとは、完全に初期化済でデータが移入されていないLOBロケータです。LONGデータ型ではロケータが使用されないため、LONGデータ型にはという概念が適用されません。

LOB列値とLONG列値はどちらも、初期値としてNULLまたは空の文字列リテラルが挿入された場合は、NULL値を持ちます。そのため、LONG列にNULLまたは長さ0(ゼロ)の値を使用するアプリケーション・コードは、列をLOB型に変換した後も同様に動作します。

対照的に、空として初期化されたLOBは、次の例に示すようにNULL以外の値を持ちます。

CREATE TABLE long_tab(id NUMBER, long_col LONG);
CREATE TABLE lob_tab(id NUMBER, lob_col CLOB);

INSERT INTO long_tab values(1, NULL);

REM     A zero length string inserts a NULL into the LONG column:
INSERT INTO long_tab values(1, ''); 

INSERT INTO lob_tab values(1, NULL);

REM     A zero length string inserts a NULL into the LOB column:
INSERT INTO lob_tab values(1, '');  

REM     Inserting an empty LOB inserts a non-NULL value: 
INSERT INTO lob_tab values(1, empty_clob());  

DROP TABLE long_tab;
DROP TABLE lob_tab;

17.5.6 アンカー型でのオーバーロード

アンカー型を使用したアプリケーションでは、LOBへの変換中に、オーバーロードされた変数が別のターゲットに解決される場合があります。たとえば、pプロシージャが指定1および2でオーバーロードされるとします。

procedure p(l long) is ...;       -- (specification 1)  
procedure p(c clob) is ...;       -- (specification 2)  

また、次のプロシージャ・コールが使用されるとします。

declare  
     var  longtab.longcol%type;  
   BEGIN  
     ...  
   p(var);  
     ...  
END;  

LONG列からLOB列に移行する前に、このコールにより指定1に解決されます。longtabがLOB列に移行すると、このコールは指定2に解決されます。これは、指定1のパラメータの型がCHARVARCHAR2RAWLONG RAWの場合も同じであることに注意してください。

表をLONG列からLOB列に移行した後、アプリケーションを手動で検査し、オーバーロードされたプロシージャの変更が必要かどうかを判断する必要があります。

移行前にLOB引数を取るオーバーロードされたプロシージャが含まれていたアプリケーションは、正常に動作しなくなる場合があります。これには、LONGのアンカー型を使用しないアプリケーションも含まれます。たとえば、pプロシージャに対する次の指定(1および2)とプロシージャ・コールを考えてみます。

procedure p(n number) is ...;       -- (1)  
procedure p(c clob) is ...;         -- (2)  
  
p('123');                 -- procedure call 

移行前には、CHARからNUMBERへの変換のみが可能であったため、指定1が選択されていました。移行後では、両方の変換が可能なため、コールの解釈が不明確になり、オーバーロード・エラーが発生します。

17.5.7 LOBデータ型に対してサポートされない一部の暗黙的変換

PL/SQLでは、NUMBERDATEROW_IDBINARY_INTEGERおよびPLS_INTEGERデータ型からLONGへの暗黙的な変換が許可されますが、これらのデータ型からLOBへの暗黙的な変換は許可されません。

アプリケーションでこの種の暗黙的な変換を使用する場合、文字データにはTO_CHAR演算子、バイナリ・データにはTO_RAW演算子を使用して、これらの型を明示的に変換する必要があります。たとえば、アプリケーションに次のような割当て操作があるとします。

number_var := long_var;  -- The RHS is a LOB variable after converting. 

この場合は、コードを次のように変更する必要があります。

number_var := TO_CHAR(long_var); 
-- Assuming that long_var is of type CLOB after conversion

LOB型の場合、次の変換はサポートされません。

  • BLOBからVARCHAR2CHARまたはLONG

  • CLOBからRAWまたはLONG RAW

これは、暗黙的な変換が発生する操作すべてに適用されます。たとえば、アプリケーションに次のようなSELECT文があるとします。

SELECT long_raw_column INTO my_varchar2 VARIABLE FROM my_table

この場合、表の変換後にlong_raw_columnBLOBになると、SELECT文でエラーが生成されます。この変換を機能させるには、次のように、TO_RAW演算子を使用してBLOBRAWに明示的に変換する必要があります。

SELECT TO_RAW(long_raw_column) INTO my_varchar2 VARIABLE FROM my_table  

CLOBRAW変数に選択する場合、CLOBRAWに割り当てる場合、およびBLOBVARCHAR2に割り当てる場合も同様です。