[Oracle] LOBデータの基本的な扱い方 | Archive Redo Blog

Archive Redo Blog

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

Oracleではサイズの大きいデータを格納するためにラージ・オブジェクト(LOB)を使用します。


LOBにはデータベース内部に格納される内部LOBとOSファイルとして格納される外部LOBの2種類がありますが、ここで説明するのは内部LOBの方です。

LOBにはバイナリー・ラージ・オブジェクト(BLOB)とキャラクター・ラージ・オブジェクト(CLOB、NCLOB)があります。

LOBデータはインライン(行データに含める)に格納するか、アウトライン(専用のLOB記憶域)に格納するかのいずれかの方式をとります。


LOB記憶域の設定で"DISABLE STORAGE IN ROW"を指定した場合、LOBデータはアウトラインに格納されます。


逆に"DISABLE STORAGE IN ROW"を指定しない場合は4,000バイトまでであればインラインに格納され、4,000バイトを超えるとアウトラインに格納されます。


また、インライン、アウトラインいずれの場合も、インラインにはLOBデータの実際の格納位置を示すLOBロケータが格納されます。


よって、ユーザーがLOBデータにアクセスする場合には、まずLOBロケータを取得し、それからLOBの読み込み/書き込みを行うという手順を踏まなくてはなりません。

(LOB記憶域の詳細についてはまた別の機会に触れます。)

LOBデータの書き込み

LOBにデータを書き込むためには、まずLOB列に対してLOBロケータを設定しなければなりません。


LOBロケータの設定はBLOB に対してはempty_blobファンクション、CLOBおよびNCLOBに対してはempty_clobファンクションを使用します。

例えば、以下のようなテーブルに対し、

CREATE TABLE TABLEA (
  COL1  NUMBER(2),
  COL2  VARCHAR2(10),
  COL3  BLOB
);

BLOBデータを含むレコードを登録する場合、以下のようにBLOB列にempty_blob()をセットしてBLOBロケータを設定する。

INSERT INTO TABLEA ( COL1, COL2, COL3 ) VALUES ( 1, 'ABC', empty_blob() );


このようにしてLOBロケータが設定できたら、そのLOBロケータを取得し、DBMS_LOBパッケージなどを利用してLOBデータを書き込みます。


このとき、まずLOBロケータを取得するためにSELECT文を実行すること、そしてそのときFOR UPDATE句を指定する必要がある点に注意しなければなりません。

SELECT COL3 INTO wk_blob FROM TABLEA FOR UPDATE;
DBMS_LOB.WRITE( wk_blob, 4000, 0, wk_buffer );


LOBデータの更新も、同様の手順で行うことができますが、既存のLOBデータをサイズの小さいLOBデータで更新する際はちょっと注意が必要です。


というのはそのまま上書きすると既存のLOBデータの末尾の部分が消されずに残ってしまうからです。

例えば、'ABCDEFGHIJKLMNOPQRSTUVWXYZ'というCLOBデータを'1234567890'というCLOBデータで更新すると、'1234567890KLMNOPQRSTUVWXYZ'なんていう中途半端なデータになってしまうのです。


この問題を防ぐには、更新後にDBMS_LOB.TRIMを使ってトリミングしてやるか、あるいは更新前にLOBデータを再初期化(empty_blob、empty_clobファンクションを使用)するなどの対処が必要になります。

LOBデータの読み込み

LOBデータを読み込むには、まず、SELECT文を実行して、LOBロケータを取得し、DBMS_LOBパッケージなどを利用してLOBロケータからLOBデータを読み込みます。


SELECT COLUMNC INTO wk_blob FROM TABLEA;
DBMS_LOB.READ( wk_blob, DBMS_LOG.GETLENGTH( wk_blob ), 0, wk_buffer );


ただし、LOBロケータがNULLの場合はちょっと注意が必要です。


LOBロケータがNULLだとLOBデータの読み込みでエラーが発生してしまうのです。


そのため、LOB列を含む行データを新規に登録する際には必ずempty_blobファンクション、empty_clobファンクションを列のデフォルト値に設定するなどしてLOBロケータがNULLにならないようにしておくか、あるいはLOBデータを読み込む前にLOBロケータがNULLかどうかを判断したほうがいいでしょう。

と、基本的にLOBは上記のように扱うわけですが、必ずLOBロケータを介さないとアクセスできない上に、読み書きするのにDBMS_LOBパッケージなどを使わなければならないのが非常にまどろっこしいところです。

だから、


「この列には普通のデータ型では収まらないようなデータが入る可能性がある。」 
→ 「じゃあLOB型にしよう。」


なんて安易な判断でLOBを使うのはよした方がいいでしょう。

LOBは使わなくて済むなら使わない方がいいです。




【関連エントリ】
[Oracle] LOBデータの基本的な扱い方 2004/12/03
[Oracle] JDBCによるLOBの操作方法 2004/12/06
[Oracle] LOBデータをファイルから直接登録する方法(その1) 2005/01/25
[Oracle] LOBデータをファイルから直接登録する方法(その2) 2005/01/27
[Oracle] LOBデータをファイルに直接出力する方法 2005/02/01
[Oracle] JavaでLOBデータを読み込む際の最適なバッファサイズは? 2005/02/02
[Oracle] LOB記憶特性 その1(STORAGE IN ROW) 2005/08/23
[Oracle] LOB記憶特性 その2(CHUNK) 2005/08/24