【Oracle】LOB(CLOB/BLOB/BFILE)完全ガイド|DBMS_LOB で読み書き・EMPTY_CLOB・一時 LOB・SecureFiles まで解説

Oracle の LOB(Large Object)データ型は、テキスト文書・画像・動画・PDF など大容量のデータを格納するための列型です。通常の VARCHAR2(最大 32767 バイト)では収まりきらないデータを格納できます。

LOB は単純に値を入れるだけでなく、DBMS_LOB パッケージを使って内容の一部を読み取る・特定文字列を検索する・データを追記するといった操作が可能です。

この記事でわかること

  • CLOB / BLOB / BFILE の違いと使い分け
  • EMPTY_CLOB() / EMPTY_BLOB() で初期化して INSERT・UPDATE する方法
  • DBMS_LOB.READ / SUBSTR / INSTR / GETLENGTH で LOB を読む方法
  • DBMS_LOB.WRITE / APPEND / ERASE で LOB を書き込む方法
  • 一時 LOB(Temporary LOB)の作成と解放
  • SecureFiles と BasicFiles の違い・SecureFiles の設定方法
スポンサーリンク

LOB の種類と使い分け

内容 最大サイズ 文字セット 格納場所
CLOB 大容量テキスト(Character Large Object) 128TB DB の文字セットに従う DB 内
NCLOB 大容量テキスト(Unicode 固定) 128TB Unicode(AL16UTF16 など) DB 内
BLOB バイナリデータ(Binary Large Object) 128TB なし(バイト列) DB 内
BFILE OS ファイルへの参照 4GB(OS 制限) OS の文字セット DB 外(参照のみ)
使い分けのポイント

  • テキストデータ(HTML・XML・ログ・長文)→ CLOB
  • 画像・PDF・動画・バイナリファイル → BLOB
  • OS 上の外部ファイルを参照するだけ(DB には格納しない)→ BFILE
  • 4000 バイト以内の短いテキストは VARCHAR2 / NVARCHAR2 を使う方が効率的

LOB を含むテーブルの定義と基本的な INSERT

LOB 列を含むテーブルの作成と INSERT
-- CLOB と BLOB を含むテーブルの作成
CREATE TABLE documents (
    doc_id       NUMBER(10)   NOT NULL,
    doc_name     VARCHAR2(200) NOT NULL,
    content      CLOB,           -- テキストデータ
    attachment   BLOB,           -- バイナリファイル
    created_at   DATE DEFAULT SYSDATE NOT NULL,
    CONSTRAINT documents_pk PRIMARY KEY (doc_id)
)
-- LOB のストレージオプション(SecureFiles を使う場合)
LOB (content)    STORE AS SECUREFILE (TABLESPACE lobdata_ts COMPRESS MEDIUM DEDUPLICATE)
LOB (attachment) STORE AS SECUREFILE (TABLESPACE lobdata_ts COMPRESS MEDIUM);

-- 短いテキストなら直接 INSERT できる(4000 バイト以内)
INSERT INTO documents (doc_id, doc_name, content)
VALUES (1, 'sample.txt', '短いテキストは直接 INSERT できます');
COMMIT;

-- 長いテキストを INSERT する(EMPTY_CLOB() で初期化 → LOB ロケーターを取得 → 更新)
INSERT INTO documents (doc_id, doc_name, content)
VALUES (2, 'report.html', EMPTY_CLOB());  -- EMPTY_CLOB() で空の CLOB を作成
COMMIT;

-- 別途 UPDATE で内容を設定する
UPDATE documents SET content = '<html><body><h1>大きなレポート</h1></body></html>'
WHERE doc_id = 2;
COMMIT;

-- BLOB の INSERT(RAW 型の文字列として小さなバイナリを直接 INSERT)
INSERT INTO documents (doc_id, doc_name, attachment)
VALUES (3, 'small.bin', EMPTY_BLOB());
COMMIT;

-- LOB セグメントのサイズを確認する
SELECT segment_name, segment_type, bytes / 1024 / 1024 AS mb
FROM USER_SEGMENTS
WHERE segment_name LIKE 'SYS_LOB%'
ORDER BY bytes DESC;

DBMS_LOB で LOB データを読む

DBMS_LOB の読み取り操作
DECLARE
    v_clob    CLOB;
    v_length  NUMBER;
    v_chunk   VARCHAR2(4000);
    v_pos     INTEGER := 1;   -- 読み取り開始位置(1から始まる)
    v_amount  INTEGER := 4000; -- 読み取るバイト数
BEGIN
    -- LOB ロケーターを取得する(FOR UPDATE なしは読み取り専用)
    SELECT content INTO v_clob
    FROM documents
    WHERE doc_id = 2;

    -- LOB の長さを取得する(バイト数)
    v_length := DBMS_LOB.GETLENGTH(v_clob);
    DBMS_OUTPUT.PUT_LINE('長さ: ' || v_length || ' バイト');

    -- LOB の一部を取得する(SUBSTR: pos から amount 文字を取得)
    v_chunk := DBMS_LOB.SUBSTR(v_clob, 100, 1);  -- 先頭から100文字
    DBMS_OUTPUT.PUT_LINE('先頭100文字: ' || v_chunk);

    -- LOB 内で文字列を検索する(INSTR: pattern が現れる位置を返す)
    DECLARE
        v_pos2 NUMBER;
    BEGIN
        v_pos2 := DBMS_LOB.INSTR(v_clob, 'body', 1, 1);  -- 'body' の最初の出現位置
        DBMS_OUTPUT.PUT_LINE('body の位置: ' || v_pos2);
    END;

    -- LOB を分割して読み取る(大容量データの処理)
    WHILE v_pos <= v_length LOOP
        DBMS_LOB.READ(v_clob, v_amount, v_pos, v_chunk);
        -- v_chunk に読み取った内容が格納される(v_amount は実際に読み取った量に変更される)
        DBMS_OUTPUT.PUT_LINE('チャンク: ' || SUBSTR(v_chunk, 1, 50) || '...');
        v_pos := v_pos + v_amount;
        v_amount := 4000;  -- 次のチャンクサイズをリセット
    END LOOP;
END;
/

DBMS_LOB で LOB データを書き込む

DBMS_LOB の書き込み操作
-- DBMS_LOB.WRITE: LOB の特定位置に書き込む
DECLARE
    v_clob   CLOB;
    v_text   VARCHAR2(4000) := '追記するテキスト';
BEGIN
    -- FOR UPDATE で LOB ロケーターを排他取得する
    SELECT content INTO v_clob
    FROM documents
    WHERE doc_id = 2
    FOR UPDATE;  -- ※ 書き込みには FOR UPDATE が必要

    -- 現在の末尾にデータを追記する(APPEND が最も便利)
    DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_text), v_text);

    -- または WRITE で特定位置に書き込む
    -- DBMS_LOB.WRITE(v_clob, length_bytes, position, data);
    -- DBMS_LOB.WRITE(v_clob, LENGTH(v_text), DBMS_LOB.GETLENGTH(v_clob) + 1, v_text);

    COMMIT;  -- COMMIT で変更が確定する
END;
/

-- DBMS_LOB.APPEND: 別の LOB を末尾に追記する
DECLARE
    v_dest CLOB;
    v_src  CLOB;
BEGIN
    SELECT content INTO v_dest FROM documents WHERE doc_id = 1 FOR UPDATE;
    SELECT content INTO v_src  FROM documents WHERE doc_id = 2;

    DBMS_LOB.APPEND(v_dest, v_src);  -- v_src を v_dest の末尾に追記する
    COMMIT;
END;
/

-- DBMS_LOB.TRIM: LOB を指定した長さに切り詰める
DECLARE
    v_clob CLOB;
BEGIN
    SELECT content INTO v_clob FROM documents WHERE doc_id = 2 FOR UPDATE;
    DBMS_LOB.TRIM(v_clob, 100);  -- 先頭100バイトだけ残して切り詰める
    COMMIT;
END;
/

-- DBMS_LOB.ERASE: LOB の特定範囲を消去する(スペースで埋める)
DECLARE
    v_clob   CLOB;
    v_amount NUMBER := 50;  -- 消去するバイト数
BEGIN
    SELECT content INTO v_clob FROM documents WHERE doc_id = 2 FOR UPDATE;
    DBMS_LOB.ERASE(v_clob, v_amount, 11);  -- 11バイト目から50バイトを消去
    COMMIT;
END;
/

一時 LOB(Temporary LOB)の使い方

一時 LOB は TEMP 表領域に作成される LOB です。大きなデータを構築してから INSERT する場合や、PL/SQL 内で一時的に大容量データを処理する際に使います。不要になったら DBMS_LOB.FREETEMPORARY で解放する必要があります。

一時 LOB の作成と解放
DECLARE
    v_clob     CLOB;
    v_chunk    VARCHAR2(4000);
BEGIN
    -- 一時 CLOB を作成する(TEMP 表領域に格納される)
    DBMS_LOB.CREATETEMPORARY(v_clob, TRUE, DBMS_LOB.SESSION);
    -- TRUE: キャッシュ有効
    -- DBMS_LOB.SESSION: セッション期間中保持(CALL スコープより長い)

    -- 一時 LOB にデータを書き込む
    v_chunk := '一時 LOB に書き込むテキスト。';
    DBMS_LOB.WRITEAPPEND(v_clob, LENGTH(v_chunk), v_chunk);

    -- 一時 LOB から読み取る
    DBMS_OUTPUT.PUT_LINE('長さ: ' || DBMS_LOB.GETLENGTH(v_clob));
    DBMS_OUTPUT.PUT_LINE('内容: ' || DBMS_LOB.SUBSTR(v_clob, 100, 1));

    -- 一時 LOB をテーブルに INSERT する(CLOB 列の値として使用)
    INSERT INTO documents (doc_id, doc_name, content)
    VALUES (10, 'temp_doc.txt', v_clob);
    COMMIT;

    -- 一時 LOB を解放する(必ず実行する)
    DBMS_LOB.FREETEMPORARY(v_clob);
EXCEPTION
    WHEN OTHERS THEN
        IF DBMS_LOB.ISTEMPORARY(v_clob) = 1 THEN
            DBMS_LOB.FREETEMPORARY(v_clob);  -- 例外時も解放する
        END IF;
        RAISE;
END;
/

SecureFiles と BasicFiles の違い

SecureFilesは Oracle 11g から導入された高機能 LOB ストレージです。従来の BasicFiles に比べてパフォーマンス・圧縮・重複排除などの機能が向上しています。11g 以降の新規テーブルでは SecureFiles の使用が推奨されます。

SecureFiles の設定と確認
-- SecureFiles を有効にするパラメータ(デフォルト DB でも設定必要)
-- 11g 以降は DB_SECUREFILE パラメータで制御する
SELECT name, value FROM V$PARAMETER WHERE name = 'db_securefile';
-- PREFERRED: SecureFiles を推奨(BasicFiles と混在可)
-- ALWAYS: 常に SecureFiles を使用
-- NEVER: 常に BasicFiles を使用

ALTER SYSTEM SET DB_SECUREFILE = PREFERRED SCOPE=BOTH;

-- SecureFiles を使ったテーブルの作成
CREATE TABLE sf_documents (
    doc_id   NUMBER(10) PRIMARY KEY,
    content  CLOB,
    image    BLOB
)
LOB (content) STORE AS SECUREFILE sf_content (
    TABLESPACE lobdata_ts
    COMPRESS MEDIUM         -- 圧縮(NONE / LOW / MEDIUM / HIGH)
    DEDUPLICATE             -- 重複排除(同じ内容の LOB は1つだけ格納)
    CACHE                   -- バッファキャッシュに格納(READ が多い場合)
    -- NOCACHE NOLOGGING: バッファキャッシュなし(一括ロード向け)
    RETENTION NONE          -- バージョン管理なし(ASSM 表領域では NONE/AUTO/MIN/MAX)
)
LOB (image) STORE AS SECUREFILE sf_image (
    TABLESPACE lobdata_ts
    COMPRESS LOW
    NOCACHE LOGGING
);

-- LOB の種類(BasicFiles か SecureFiles か)を確認する
SELECT table_name, column_name, securefile
FROM USER_LOBS
ORDER BY table_name;
-- securefile: YES(SecureFiles)/ NO(BasicFiles)

-- SecureFiles に変換する(既存の BasicFiles テーブルを SecureFiles に変換)
ALTER TABLE documents MOVE LOB(content) STORE AS SECUREFILE;
ALTER TABLE documents MOVE LOB(attachment) STORE AS SECUREFILE;
-- ※ MOVE は一時的にテーブルをロックする。DBMS_REDEFINITION でオンライン変換も可

まとめ

  • LOB の種類:テキストは CLOB、バイナリは BLOB、外部ファイルは BFILE。4000 バイト以内なら VARCHAR2/RAW の方が効率的
  • INSERT の注意点:小さなデータは直接 INSERT 可。大きなデータは EMPTY_CLOB()/EMPTY_BLOB() で初期化して FOR UPDATE で LOB ロケーターを取得してから DBMS_LOB で書き込む
  • DBMS_LOB の主要操作:GETLENGTH(長さ取得)・SUBSTR(部分取得)・INSTR(検索)・READ(チャンク読み取り)・WRITEAPPEND(末尾追記)・APPEND(LOB 同士の結合)
  • 一時 LOB:CREATETEMPORARY で TEMP 表領域に作成し、不要になったら FREETEMPORARY で解放する。例外処理でも解放を忘れないこと
  • SecureFiles:11g 以降の推奨 LOB ストレージ。圧縮・重複排除・暗号化が使える。DB_SECUREFILE=PREFERRED を設定して LOB … STORE AS SECUREFILE で指定する

LOB データの CLOB を VARCHAR2 に変換する方法や、DBMS_LOB.SUBSTR で取得した値の加工には Oracle 文字列関数完全ガイドを参照してください。UTL_FILE を使ったファイルとの読み書きについては Oracle UTL_FILE 完全ガイドも参照してください。