Oracleデータベースで大きなデータを格納するLOB(Large Object)カラムは、内部的にLOBセグメントという専用領域にデータを保持します。テーブルの容量が肥大化した原因がLOBにある、というケースは非常に多く、LOBセグメントのサイズ確認は運用・チューニングの基本スキルです。
この記事では、DBA_LOBSでのLOB一覧確認から、DBA_SEGMENTSでのサイズ取得、DBMS_LOB.GETLENGTHでの実データサイズ確認、表領域別集計、断片化調査まで、実務で必要なパターンを体系的に解説します。
この記事で学べること
- CLOB・BLOB・NCLOBの違いとLOBセグメントの仕組み
- USER_LOBS・DBA_LOBSでLOBセグメントを一覧確認する方法
- DBA_SEGMENTSでLOBセグメントのサイズをMB/GB単位で取得する方法
- DBMS_LOB.GETLENGTHで実データサイズを確認する方法
- 表領域ごとのLOB使用量を集計するSQL
- BasicFile/SecureFile判定・断片化・IN-ROW/OUT-OF-ROWの実務知識
LOBセグメントとは
LOB(Large Object)は、テキスト・バイナリ・XMLなどの大きなデータを格納するためのデータ型です。Oracleでは、LOBカラムのデータはテーブルセグメントとは別の「LOBセグメント」に格納されます(デフォルトでは4KB超のデータ)。
| データ型 |
格納内容 |
最大サイズ |
用途例 |
| CLOB |
文字データ(DBキャラクタセット) |
最大 (4GB – 1) × DBブロックサイズ |
長文テキスト、XMLデータ |
| BLOB |
バイナリデータ |
最大 (4GB – 1) × DBブロックサイズ |
画像、PDF、動画ファイル |
| NCLOB |
文字データ(Nationalキャラクタセット) |
最大 (4GB – 1) × DBブロックサイズ |
多言語テキスト |
SYS_LOB命名規則
Oracleは LOBカラムを作成すると、自動的に SYS_LOB0000012345C00003$$ のような名前でLOBセグメントを生成します。数字部分はテーブルのOBJECT_IDとカラム番号に対応しています。DBA_LOBSビューで、どのテーブル・カラムに紐づくかを確認できます。
LOBセグメントの一覧確認(USER_LOBS・DBA_LOBS)
まず、データベース内にどのようなLOBセグメントが存在するかを確認します。自スキーマ内の確認にはUSER_LOBS、全スキーマの確認にはDBA_LOBSを使います。
自スキーマのLOB一覧を確認(USER_LOBS)
SELECT
table_name,
column_name,
segment_name,
tablespace_name,
index_name
FROM user_lobs
ORDER BY table_name, column_name;
実行結果例
TABLE_NAME COLUMN_NAME SEGMENT_NAME TABLESPACE_NAME INDEX_NAME
------------ ------------ ------------------------ ---------------- --------------------------
DOCUMENTS CONTENT SYS_LOB0000078523C00003$$ USERS SYS_IL0000078523C00003$$
IMAGES FILE_DATA SYS_LOB0000078530C00004$$ USERS SYS_IL0000078530C00004$$
LOGS LOG_TEXT SYS_LOB0000078542C00002$$ USERS SYS_IL0000078542C00002$$
全スキーマを横断して確認したい場合はDBA_LOBSを使います(DBA権限が必要)。
全スキーマのLOB一覧を確認(DBA_LOBS)
SELECT
owner,
table_name,
column_name,
segment_name,
tablespace_name
FROM dba_lobs
WHERE owner NOT IN ('SYS', 'SYSTEM', 'MDSYS', 'XDB')
ORDER BY owner, table_name;
ポイント:WHERE owner NOT IN ('SYS', 'SYSTEM', ...) でシステムスキーマを除外すると、アプリケーションのLOBだけに絞り込めます。
LOBセグメントのサイズ確認(DBA_SEGMENTS)
LOBセグメントが使用しているディスク上のサイズを確認するには、DBA_SEGMENTSビューを使います。DBA_LOBSと結合して、テーブル名・カラム名付きで表示するのが実務の定番です。
LOBセグメントのサイズをMB単位で取得
SELECT
l.owner,
l.table_name,
l.column_name,
s.segment_name,
ROUND(s.bytes / 1024 / 1024, 2) AS size_mb
FROM dba_segments s
JOIN dba_lobs l
ON s.owner = l.owner
AND s.segment_name = l.segment_name
WHERE l.owner = 'HR'
ORDER BY size_mb DESC;
実行結果例
OWNER TABLE_NAME COLUMN_NAME SEGMENT_NAME SIZE_MB
------ ----------- ------------ ------------------------- -------
HR DOCUMENTS CONTENT SYS_LOB0000078523C00003$$ 512.00
HR IMAGES FILE_DATA SYS_LOB0000078530C00004$$ 256.50
HR LOGS LOG_TEXT SYS_LOB0000078542C00002$$ 48.25
GB単位で表示したい場合は、ROUND(s.bytes / 1024 / 1024 / 1024, 2) に変更してください。
DB全体のLOBセグメントサイズ TOP10
容量を消費しているLOBの上位を素早く特定するSQLです。
LOBセグメント サイズTOP10
SELECT *
FROM (
SELECT
l.owner,
l.table_name,
l.column_name,
ROUND(s.bytes / 1024 / 1024, 2) AS size_mb,
ROUND(s.bytes / 1024 / 1024 / 1024, 3) AS size_gb
FROM dba_segments s
JOIN dba_lobs l
ON s.owner = l.owner
AND s.segment_name = l.segment_name
WHERE l.owner NOT IN ('SYS', 'SYSTEM')
ORDER BY s.bytes DESC
)
WHERE ROWNUM <= 10;
LOBカラムの実データサイズ(DBMS_LOB.GETLENGTH)
DBA_SEGMENTSで取得するサイズはセグメントに割り当てられた領域(=ディスク上の確保済みサイズ)です。一方、実際にLOBカラムに格納されているデータの合計サイズを知りたい場合は、DBMS_LOB.GETLENGTHを使います。
| 比較項目 |
セグメントサイズ(DBA_SEGMENTS) |
実データサイズ(DBMS_LOB.GETLENGTH) |
| 意味 |
ディスク上の確保済み領域 |
実際に格納されたデータ量 |
| 大小関係 |
通常、実データより大きい |
セグメントサイズ以下 |
| 差が大きい場合 |
DELETE後に領域が解放されていない(断片化)の可能性 |
| 確認用途 |
表領域の容量計画 |
データ量の把握、移行見積り |
LOBカラムの実データサイズ合計をMBで取得
SELECT
COUNT(*) AS row_count,
ROUND(SUM(DBMS_LOB.GETLENGTH(content)) / 1024 / 1024, 2) AS data_mb
FROM documents
WHERE content IS NOT NULL;
実行結果例
ROW_COUNT DATA_MB
---------- -------
15230 384.72
行ごとの個別サイズを確認したい場合は以下のようにします。
行ごとのLOBサイズを確認(上位10件)
SELECT *
FROM (
SELECT
id,
DBMS_LOB.GETLENGTH(content) AS lob_bytes,
ROUND(DBMS_LOB.GETLENGTH(content) / 1024, 1) AS lob_kb
FROM documents
WHERE content IS NOT NULL
ORDER BY lob_bytes DESC
)
WHERE ROWNUM <= 10;
注意:DBMS_LOB.GETLENGTHはCLOBの場合は文字数、BLOBの場合はバイト数を返します。CLOBのバイト数が必要な場合は、LENGTHBを使うか、キャラクタセットのバイト数を掛けて概算してください。
表領域ごとのLOB使用量を集計する
表領域の容量計画では、LOBセグメントが各表領域でどれだけ使用しているかを把握することが重要です。
表領域ごとのLOB使用量(GB単位)
SELECT
l.tablespace_name,
COUNT(*) AS lob_count,
ROUND(SUM(s.bytes) / 1024 / 1024 / 1024, 2) AS total_gb
FROM dba_segments s
JOIN dba_lobs l
ON s.owner = l.owner
AND s.segment_name = l.segment_name
WHERE l.owner NOT IN ('SYS', 'SYSTEM')
GROUP BY l.tablespace_name
ORDER BY total_gb DESC;
実行結果例
TABLESPACE_NAME LOB_COUNT TOTAL_GB
----------------- ---------- --------
LOB_DATA 12 8.45
USERS 5 2.13
APP_DATA 3 0.87
テーブルセグメントとLOBセグメントの合計サイズを比較したい場合は、以下のようにします。
テーブル本体 vs LOBセグメント サイズ比較
SELECT
l.owner,
l.table_name,
ROUND(t.bytes / 1024 / 1024, 2) AS table_mb,
ROUND(SUM(ls.bytes) / 1024 / 1024, 2) AS lob_mb,
ROUND((SUM(ls.bytes) / NULLIF(t.bytes, 0)) * 100, 1) AS lob_pct
FROM dba_lobs l
JOIN dba_segments ls
ON l.owner = ls.owner AND l.segment_name = ls.segment_name
JOIN dba_segments t
ON l.owner = t.owner AND l.table_name = t.segment_name
AND t.segment_type = 'TABLE'
WHERE l.owner = 'HR'
GROUP BY l.owner, l.table_name, t.bytes
ORDER BY lob_mb DESC;
実務パターンと注意点
BasicFile / SecureFile の判定
Oracle 11g以降では、LOBの格納形式としてBasicFile(従来型)とSecureFile(高速・圧縮対応)の2種類があります。パフォーマンスと容量に影響するため、どちらが使われているか確認しましょう。
BasicFile / SecureFile の確認
SELECT
owner,
table_name,
column_name,
securefile
FROM dba_lobs
WHERE owner = 'HR'
ORDER BY table_name;
実行結果例
OWNER TABLE_NAME COLUMN_NAME SECUREFILE
------ ----------- ------------ ----------
HR DOCUMENTS CONTENT YES
HR IMAGES FILE_DATA NO
HR LOGS LOG_TEXT YES
| 比較項目 |
BasicFile |
SecureFile |
| 圧縮 |
非対応 |
LOW / MEDIUM / HIGH |
| 重複排除 |
非対応 |
対応 |
| 暗号化 |
非対応 |
対応 |
| パフォーマンス |
従来型 |
高速(推奨) |
LOBの断片化を調査する
LOBデータの大量DELETE後、セグメントサイズが減らないことがあります。これは断片化が原因です。セグメントサイズと実データサイズを比較して断片化の度合いを確認しましょう。
LOB断片化の確認(セグメント vs 実データ)
SELECT
seg.size_mb AS segment_mb,
data.data_mb AS actual_data_mb,
ROUND(seg.size_mb - data.data_mb, 2) AS wasted_mb,
ROUND((1 - data.data_mb / NULLIF(seg.size_mb, 0)) * 100, 1) AS waste_pct
FROM (
SELECT ROUND(bytes / 1024 / 1024, 2) AS size_mb
FROM dba_segments
WHERE segment_name = (
SELECT segment_name FROM dba_lobs
WHERE owner = 'HR' AND table_name = 'DOCUMENTS'
AND column_name = 'CONTENT'
)
) seg,
(
SELECT ROUND(SUM(DBMS_LOB.GETLENGTH(content)) / 1024 / 1024, 2) AS data_mb
FROM hr.documents
WHERE content IS NOT NULL
) data;
実行結果例(断片化あり)
SEGMENT_MB ACTUAL_DATA_MB WASTED_MB WASTE_PCT
---------- --------------- ---------- ---------
512.00 384.72 127.28 24.9
断片化が大きい場合の対処法:
- SecureFile LOB:
ALTER TABLE ... MOVE LOB (column) STORE AS (...) で再編成
- BasicFile LOB:
ALTER TABLE ... MOVE でテーブルごと再編成
- 再編成後はインデックスのREBUILDが必要です
IN-ROW / OUT-OF-ROW 格納の確認
LOBデータは、サイズが小さい場合はテーブル行内(IN-ROW)に、大きい場合は別セグメント(OUT-OF-ROW)に格納されます。デフォルトでは約4KB以下がIN-ROW格納です。
IN-ROW格納の設定確認
SELECT
table_name,
column_name,
in_row
FROM dba_lobs
WHERE owner = 'HR'
ORDER BY table_name;
ポイント:IN-ROW=YESの場合、小さなLOBデータはテーブルセグメント内に格納されるため、LOBセグメントのサイズだけでは全容量を把握できません。大量の小さなLOBがある場合は、テーブルセグメントのサイズも合わせて確認してください。
まとめ
OracleのLOBセグメントに関する確認・サイズ取得方法を整理しました。最後に、用途別のSQL早見表をまとめます。
| やりたいこと |
使用するビュー/関数 |
権限 |
| 自スキーマのLOB一覧 |
USER_LOBS |
不要 |
| 全スキーマのLOB一覧 |
DBA_LOBS |
DBA権限 |
| LOBセグメントのディスクサイズ |
DBA_SEGMENTS + DBA_LOBS |
DBA権限 |
| LOBの実データサイズ |
DBMS_LOB.GETLENGTH |
テーブルへのSELECT |
| 表領域別LOB集計 |
DBA_SEGMENTS + DBA_LOBS + GROUP BY |
DBA権限 |
| BasicFile/SecureFile判定 |
DBA_LOBS.SECUREFILE |
DBA権限 |
| 断片化調査 |
DBA_SEGMENTS + DBMS_LOB.GETLENGTH |
DBA権限 + SELECT |
LOBセグメントのサイズ管理は、テーブル容量が肥大化した際のトラブルシューティングや、定期的な容量監視において欠かせません。特にセグメントサイズと実データサイズの乖離(断片化)に注目し、必要に応じて再編成を検討してください。