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 完全ガイドも参照してください。