Oracle テーブルサイズ確認の完全ガイド:SQLとビューの詳細解説
はじめに:なぜOracleテーブルのサイズを知る必要があるのか?
Oracleデータベースを運用する上で、テーブルのサイズを正確に把握することは非常に重要です。なぜなら、テーブルサイズはデータベースの様々な側面に直接的、あるいは間接的に影響を与えるからです。
- 容量計画 (Capacity Planning): データベース全体のディスク容量だけでなく、将来的なデータ増加によるストレージ要件を見積もるために、各テーブルが現在どれだけの容量を使用しているかを知ることは不可欠です。特に、データが急速に増加する可能性のあるテーブル(トランザクションログ、イベントログ、履歴データなど)のサイズ推移を把握することで、ストレージ逼迫によるシステム停止などのリスクを回避できます。
- パフォーマンスチューニング (Performance Tuning): 大規模なテーブルに対するクエリは、パフォーマンス問題を引き起こす主要な原因の一つです。特定のテーブルが異常に大きい場合、そのテーブルへのアクセス方法(インデックスの適切性、SQLクエリの効率性、パーティショニングの導入など)を見直す必要が出てきます。また、テーブルサイズの増加は、統計情報の鮮度維持や、インデックスの再構築・再構成の必要性にも関わってきます。
- ディスク領域管理 (Disk Space Management): データベースが使用するディスク領域は、テーブル、インデックス、LOBセグメントなどのセグメントによって消費されます。どのテーブルやオブジェクトが多くの領域を占めているかを特定することで、不要なデータの削除、古いパーティションのアーカイブ/パージ、またはデータ圧縮の検討など、具体的なディスク領域解放・最適化策を講じることができます。
- バックアップとリカバリ (Backup and Recovery): テーブルサイズが大きいということは、そのバックアップやリカバリにかかる時間、および必要なストレージ容量が増加することを意味します。重要な大規模テーブルのバックアップ戦略やリカバリ時間を適切に見積もるためにも、サイズ情報は不可欠です。
- コスト管理 (Cost Management): クラウド環境など従量課金制のストレージを使用している場合、テーブルサイズは直接的にコストに影響します。サイズの大きなテーブルを特定し、最適化することでコスト削減につながる可能性があります。
このように、テーブルサイズの確認は、単なる好奇心からではなく、データベースの安定稼働、パフォーマンス維持、コスト最適化、そして将来計画のために不可欠な運用タスクと言えます。
本記事では、Oracleデータベースにおいてテーブルサイズを正確に、あるいは推定で確認するために使用する主要なSQLクエリと、その基盤となるデータディクショナリビューについて、詳細かつ網羅的に解説します。セグメント情報に基づく実サイズの確認方法、統計情報に基づく推定サイズの確認方法、そしてパーティションテーブルやLOB列を含むテーブルのサイズ確認方法についても触れます。
Oracleのストレージ構造の基本
テーブルサイズを確認するためのSQLやビューを理解するには、Oracleがデータをどのようにストレージに格納しているかの基本的な構造を把握しておく必要があります。Oracleのストレージ構造は階層的になっています。
- データベース (Database): データベース全体を指します。一つ以上の制御ファイル、データファイル、REDOログファイルから構成されます。
- 表領域 (Tablespace): データファイルの上に位置する論理的なストレージ単位です。一つ以上のデータファイルを包含し、様々なデータベースオブジェクト(テーブル、インデックスなど)を格納するための領域を提供します。ユーザーはオブジェクトを作成する際に、どの表領域に配置するかを指定できます。表領域は、データの種類やアクセスパターンによって分けられることが一般的です(例: SYSTEM, SYSAUX, UNDO, TEMP, ユーザーデータ用、インデックス用など)。
- セグメント (Segment): 特定の種類のデータベースオブジェクトが使用するストレージ領域のことです。テーブル、インデックス、LOB、UNDO、一時セグメントなどがセグメントを持ちます。テーブルを作成すると、通常、そのテーブルのためのセグメントが一つ作成されます。パーティションテーブルの場合は、パーティションごとにセグメントが作成されます。セグメントは一つ以上のエクステントから構成されます。
- エクステント (Extent): ストレージ確保の基本的な単位です。連続したデータブロックの集合からなります。セグメントが必要とする領域は、一つ以上のエクステントによって提供されます。データが増加して現在のエクステントが満杯になると、Oracleはセグメントに新しいエクステントを割り当てます。
- データブロック (Data Block): Oracleがデータを読み書きする際の最小単位です。オペレーティングシステムのブロックサイズや、データベース作成時に指定されるDB_BLOCK_SIZEパラメータによってサイズが決まります(通常 4KB, 8KB, 16KBなど)。テーブルの行データはデータブロック内に格納されます。
(画像はOracle公式ドキュメントなどを参考にイメージしてください。表領域 > セグメント > エクステント > データブロック の階層です)
テーブルサイズを確認する際に最も頻繁に使用するのは、「セグメント」レベルの情報です。なぜなら、テーブルが実際に使用しているディスク上の容量は、そのテーブル本体のセグメント、関連するインデックスのセグメント、LOB列があればそのLOBセグメントなどの合計だからです。データディクショナリビューであるDBA_SEGMENTS(またはALL_SEGMENTS, USER_SEGMENTS)は、このセグメントレベルでの詳細な情報を提供してくれます。
Oracleテーブルサイズ確認のための主要なビュー
Oracleのデータディクショナリには、データベースに関する様々なメタ情報が格納されています。テーブルサイズを確認するために主に使用されるのは以下のビューです。これらのビューには、権限に応じて DBA_, ALL_, USER_ というプレフィックスが付いたものがあります。
DBA_: データベース全体の情報を参照できます。通常、DBA権限が必要です。最も包括的な情報を提供します。ALL_: 現在接続しているユーザーがアクセス権限を持つオブジェクトに関する情報を参照できます。USER_: 現在接続しているユーザーが所有するオブジェクトに関する情報を参照できます。
本記事では、主にDBA_ビューを中心に解説しますが、適切な権限がない場合はALL_ビューやUSER_ビューを使用してください。ALL_ビューやUSER_ビューを使用する際は、OWNER列がなくなるなど、一部列構成が異なる場合があることに注意が必要です。
1. DBA_SEGMENTS / ALL_SEGMENTS / USER_SEGMENTS
これらのビューは、データベース内の各セグメントに関する詳細な情報を提供します。テーブルが物理的にどれだけの領域を使用しているかを知る上で、最も信頼できる情報源となります。セグメント単位での正確なサイズ(割り当てられているディスク領域の合計)を確認できます。
主要な列:
OWNER(VARCHAR2): セグメントを所有するユーザー(スキーマ)名。SEGMENT_NAME(VARCHAR2): セグメントの名前。テーブル本体のセグメントの場合、通常はテーブル名と同じです。インデックスやLOBセグメントの場合は、対応するインデックス名やシステム生成された名前になります。SEGMENT_TYPE(VARCHAR2): セグメントの種類。主な種類としてTABLE,INDEX,LOBSEGMENT,LOBINDEX,ROLLBACK,DEFERRED_ROLLBACK,TEMPORARY,TYPE2 UNDOなどがあります。テーブル本体のサイズを確認する場合はTABLEタイプ、インデックスのサイズを確認する場合はINDEXタイプ、LOB列のサイズを確認する場合はLOBSEGMENTタイプを参照します。TABLESPACE_NAME(VARCHAR2): セグメントが配置されている表領域の名前。HEADER_FILE(NUMBER): セグメントのヘッダーブロックを含むデータファイル番号。HEADER_BLOCK(NUMBER): セグメントのヘッダーブロックのブロック番号。BYTES(NUMBER): セグメントが割り当てられている合計バイト数。この列がセグメントの実際のサイズを示します。BLOCKS(NUMBER): セグメントが割り当てられている合計データブロック数。BYTESをDB_BLOCK_SIZEで割った値にほぼ等しくなります。EXTENTS(NUMBER): セグメントに割り当てられているエクステントの数。INITIAL_EXTENT(NUMBER): 最初の初期エクステントのサイズ(バイト)。NEXT_EXTENT(NUMBER): 次に新しいエクステントを割り当てる場合のサイズ(バイト)。MIN_EXTENTS(NUMBER): セグメント作成時に最初に割り当てるエクステントの最小数。MAX_EXTENTS(NUMBER): セグメントに割り当て可能なエクステントの最大数。
基本的なSQLクエリ例:
特定のテーブル本体のサイズをバイト単位で確認する:
sql
SELECT
owner,
segment_name,
segment_type,
tablespace_name,
bytes,
blocks,
extents
FROM
dba_segments
WHERE
segment_type = 'TABLE'
AND owner = 'YOUR_SCHEMA_NAME' -- 確認したいスキーマ名に置き換えてください
AND segment_name = 'YOUR_TABLE_NAME'; -- 確認したいテーブル名に置き換えてください
特定のテーブルに関連するすべてのセグメント(本体、インデックス、LOBなど)の合計サイズを確認する:
テーブル名と同じ名前のセグメントだけでなく、インデックスやLOBセグメントもそのテーブルに関連付けられています。これらのセグメント名にはテーブル名が含まれる場合や、他の命名規則に従う場合があります。厳密に関連するセグメントを特定するには、DBA_OBJECTS や DBA_INDEXES, DBA_LOBS など他のビューとの結合が必要になりますが、簡易的に特定のテーブル名に関連するセグメントを抽出するには、SEGMENT_NAME や OWNER でフィルタリングし、合計します。
sql
-- テーブル本体と、そのテーブル名を含むインデックスやLOBセグメントなど、関連する可能性のあるセグメントの合計サイズ
-- (注意: これだけでは不十分な場合がある。後述のJOINを使った方法がより正確)
SELECT
SUM(bytes) AS total_bytes
FROM
dba_segments
WHERE
owner = 'YOUR_SCHEMA_NAME' -- 確認したいスキーマ名に置き換えてください
AND segment_name LIKE 'YOUR_TABLE_NAME%'; -- テーブル名を含むセグメント名を検索(ワイルドカード使用)
より正確にテーブルに関連する全てのセグメント(本体、インデックス、LOB)の合計サイズを確認する方法は、後述のSQL例で詳しく説明します。
DBA_SEGMENTSビューは、セグメントが現在割り当てられている領域のサイズを示します。これは、セグメントが実際に使用している領域(データが格納されている部分)とは異なる場合があります。特に、データの削除や更新によってブロック内の空き領域が増加したり、エクステントが解放されずにセグメントに割り当てられたままになったりした場合、BYTESの値は実際のデータ量よりも大きくなります。しかし、Oracleが領域を解放してOSに戻すのは通常セグメント全体または特定のパーティション全体をDROP/TRUNCATEした場合や、Shrink Space操作を行った場合のみです。そのため、一般的にはDBA_SEGMENTSのBYTES列が、そのセグメントがディスク上で占めている物理的なサイズを示すと理解して差し支えありません。
2. DBA_TABLES / ALL_TABLES / USER_TABLES
これらのビューは、各テーブルに関するメタ情報を提供します。セグメントサイズのような物理的な情報だけでなく、テーブルの論理的な特性や、オプティマイザ統計に関する情報も含まれます。統計情報(行数や平均行長)を使用して、テーブルのおおよそのサイズを推定することができますが、これはあくまで推定値であり、統計情報の鮮度に依存します。
主要な列:
OWNER(VARCHAR2): テーブルを所有するユーザー(スキーマ)名。TABLE_NAME(VARCHAR2): テーブルの名前。TABLESPACE_NAME(VARCHAR2): テーブルが配置されている表領域の名前。CLUSTER_NAME(VARCHAR2): テーブルがクラスターの一部である場合、そのクラスター名。IOT_TYPE(VARCHAR2): インデックス構成表(IOT)の場合、そのタイプ。PCT_FREE(NUMBER): ブロック内の空き領域として確保しておく割合。更新のために予約されます。PCT_USED(NUMBER): ブロックの使用率がこの値を下回ると、そのブロックは新規行挿入の候補になります。INI_TRANS(NUMBER): 各データブロックの初期トランザクションスロット数。MAX_TRANS(NUMBER): 各データブロックの最大トランザクションスロット数。INITIAL_EXTENT(NUMBER): 初期エクステントのサイズ(バイト)。NEXT_EXTENT(NUMBER): 次に新しいエクステントを割り当てる場合のサイズ(バイト)。MIN_EXTENTS(NUMBER): 最小エクステント数。MAX_EXTENTS(NUMBER): 最大エクステント数。PCT_INCREASE(NUMBER): 次のエクステントサイズを決定する際の増加率(ディクショナリ管理表領域の場合)。FREELISTS(NUMBER): セグメント内のフリーリストグループ数。FREELIST_GROUPS(NUMBER): プロセスがインスタンスに割り当てられるフリーリストグループ数。LOGGING(VARCHAR2): ロギングモード (YES/NO).BACKED_UP(VARCHAR2): バックアップされているか (Y/N).NUM_ROWS(NUMBER): テーブル内の行数。オプティマイザ統計情報に基づきます。AVG_ROW_LEN(NUMBER): 行の平均長(バイト)。オプティマイザ統計情報に基づきます。BLOCKS(NUMBER): テーブル本体セグメントに割り当てられているブロック数。DBA_SEGMENTSのBLOCKSとほぼ同じですが、統計情報に基づくため、若干古い場合があります。EMPTY_BLOCKS(NUMBER): セグメントに割り当てられているが、データが全く格納されていないブロック数。AVG_SPACE(NUMBER): 各ブロックの平均空き領域(バイト)。CHAIN_CNT(NUMBER): 行移行または行連鎖が発生している行数。DEGREE(VARCHAR2): 並列処理の並列度。INSTANCES(VARCHAR2): 並列処理におけるインスタンス数。CACHE(VARCHAR2): テーブルがキャッシュされているか (Y/N).TABLE_LOCK(VARCHAR2): テーブルロックモード (ENABLED/DISABLED).SAMPLE_SIZE(NUMBER): 統計情報の収集に使用された行数。LAST_ANALYZED(DATE): 統計情報が最後に収集された日時。この日時を確認することで、統計情報がどの程度古いかを判断できます。COMPRESSION(VARCHAR2): 圧縮が有効か (ENABLED/DISABLED/NO_COMPRESSION).COMPRESS_FOR(VARCHAR2): 圧縮レベル (BASIC,OLTP,ARCHIVE LOW,ARCHIVE HIGHなど).DROPPED(VARCHAR2): テーブルがDROPされた後、PURGEされずに残っているか (YES/NO).
基本的なSQLクエリ例:
特定のテーブルの統計情報を確認する:
sql
SELECT
owner,
table_name,
tablespace_name,
num_rows,
avg_row_len,
blocks,
empty_blocks,
last_analyzed
FROM
dba_tables
WHERE
owner = 'YOUR_SCHEMA_NAME' -- 確認したいスキーマ名に置き換えてください
AND table_name = 'YOUR_TABLE_NAME'; -- 確認したいテーブル名に置き換えてください
NUM_ROWSとAVG_ROW_LENを使った推定サイズ(バイト)の計算:
sql
SELECT
owner,
table_name,
num_rows * avg_row_len AS estimated_bytes, -- 推定サイズ(バイト)
num_rows,
avg_row_len,
last_analyzed
FROM
dba_tables
WHERE
owner = 'YOUR_SCHEMA_NAME' -- 確認したいスキーマ名に置き換えてください
AND table_name = 'YOUR_TABLE_NAME' -- 確認したいテーブル名に置き換えてください
AND num_rows IS NOT NULL -- 統計情報が存在する場合のみ
AND avg_row_len IS NOT NULL;
注意点: NUM_ROWSとAVG_ROW_LENは、最後に統計情報が収集された時点の値です。データが頻繁に更新・挿入・削除されるテーブルでは、これらの値はすぐに古くなり、実際のサイズとの乖離が大きくなります。LAST_ANALYZED列を確認して、統計情報の鮮度を必ずチェックしてください。正確なサイズが必要な場合は、DBA_SEGMENTSの情報を参照する必要があります。統計情報は、あくまでおおよその傾向や、データの増加率を把握するための参考として使用するのが一般的です。
3. DBA_OBJECTS / ALL_OBJECTS / USER_OBJECTS
これらのビューは、データベース内のすべてのオブジェクトに関する基本的な情報を提供します。オブジェクトの名前、タイプ、作成日などの情報が含まれます。テーブルサイズ確認においては、特定のテーブルに関連する様々なオブジェクト(インデックス、LOBなど)を特定するために、他のビューと組み合わせて使用されることがあります。
主要な列:
OWNER(VARCHAR2): オブジェクトを所有するユーザー(スキーマ)名。OBJECT_NAME(VARCHAR2): オブジェクトの名前。OBJECT_ID(NUMBER): オブジェクトのID。DATA_OBJECT_ID(NUMBER): オブジェクトのデータセグメントのID。パーティションやLOBなども含め、ストレージを使用する単位ごとのID。OBJECT_TYPE(VARCHAR2): オブジェクトのタイプ。TABLE,INDEX,VIEW,SEQUENCE,PROCEDURE,FUNCTION,PACKAGE,PACKAGE BODY,TRIGGER,LOB,PARTITION,SUBPARTITIONなど多数あります。CREATED(DATE): オブジェクトが作成された日時。LAST_DDL_TIME(DATE): オブジェクトに対して最後にDDLが実行された日時。STATUS(VARCHAR2): オブジェクトの状態 (VALID,INVALIDなど).GENERATED(VARCHAR2): システム生成されたオブジェクトか (Y/N).TEMPORARY(VARCHAR2): 一時オブジェクトか (Y/N).SECONDARY(VARCHAR2): セカンダリオブジェクトか (Y/N).NAMESPACE(NUMBER): オブジェクトの名前空間。EDITION_NAME(VARCHAR2): オブジェクトが属するエディションの名前。SHARING(VARCHAR2): オブジェクトの共有属性 (NONE,METADATA,DATA,EXTENDED DATA).EDITIONABLE(VARCHAR2): エディション化可能か (Y/N).ORACLE_MAINTAINED(VARCHAR2): Oracleがメンテナンスしているオブジェクトか (Y/N).
DBA_OBJECTS自体にはサイズ情報はありませんが、例えば特定のテーブルに関連するインデックス名やLOB名を知りたい場合に、OBJECT_TYPEをフィルタリングして使用します。
基本的なSQLクエリ例:
特定のテーブルに関連するオブジェクトをリストアップする:
sql
SELECT
owner,
object_name,
object_type,
created,
last_ddl_time,
status
FROM
dba_objects
WHERE
owner = 'YOUR_SCHEMA_NAME' -- 確認したいスキーマ名に置き換えてください
-- テーブル本体だけでなく、関連するオブジェクトも検索する場合
AND ( object_name = 'YOUR_TABLE_NAME' -- テーブル本体
OR object_name IN ( SELECT index_name FROM dba_indexes WHERE owner = 'YOUR_SCHEMA_NAME' AND table_name = 'YOUR_TABLE_NAME' ) -- 関連インデックス
OR object_name IN ( SELECT segment_name FROM dba_lobs WHERE owner = 'YOUR_SCHEMA_NAME' AND table_name = 'YOUR_TABLE_NAME' ) -- 関連LOBセグメント
OR object_name IN ( SELECT index_name FROM dba_lobs WHERE owner = 'YOUR_SCHEMA_NAME' AND table_name = 'YOUR_TABLE_NAME' ) -- 関連LOBインデックス
-- パーティションテーブルの場合は PARTITION や SUBPARTITION も考慮する必要がある
)
ORDER BY
object_type, object_name;
このように、DBA_OBJECTSは他のビューと組み合わせて使用することで、テーブル構造や関連オブジェクトの特定に役立ちます。
テーブルサイズを計算するための具体的なSQLクエリ例
ここからは、前述のビューを組み合わせて、様々な角度からテーブルサイズを確認する具体的なSQLクエリを紹介します。
1. テーブル本体のみのサイズを確認する (DBA_SEGMENTS)
最もシンプルかつ正確な、テーブル本体(データ行が格納されているセグメント)のサイズを確認する方法です。
sql
SELECT
s.owner,
s.segment_name AS table_name,
s.tablespace_name,
s.bytes, -- バイト単位のサイズ
ROUND(s.bytes / 1024, 2) AS size_kb, -- KB単位に変換
ROUND(s.bytes / (1024*1024), 2) AS size_mb, -- MB単位に変換
ROUND(s.bytes / (1024*1024*1024), 2) AS size_gb -- GB単位に変換
FROM
dba_segments s
WHERE
s.segment_type = 'TABLE' -- セグメントタイプが 'TABLE' であること
AND s.owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
AND s.segment_name = 'YOUR_TABLE_NAME'; -- テーブル名を指定
このクエリは、指定したスキーマ/テーブル名のテーブル本体セグメントが現在割り当てている領域のサイズを返します。単位変換のために1024で割っています。
2. 特定のテーブルに関連する全てのセグメントの合計サイズを確認する (DBA_SEGMENTS, DBA_TABLES, DBA_INDEXES, DBA_LOBSの結合)
テーブルが実際に使用している領域は、テーブル本体だけでなく、そのテーブルに作成されたインデックスやLOBセグメント、LOBインデックスの合計サイズです。これらの関連オブジェクトを正確に特定し、そのセグメントサイズの合計を算出します。
“`sql
— CTE (Common Table Expression) を使用して、対象テーブルに関連するセグメント名を特定し、
— その後 DBA_SEGMENTS からサイズを取得して合計するクエリ
WITH TableRelatedSegments AS (
— テーブル本体のセグメント名
SELECT owner, segment_name, segment_type
FROM dba_segments
WHERE owner = ‘YOUR_SCHEMA_NAME’ AND segment_name = ‘YOUR_TABLE_NAME’ AND segment_type = ‘TABLE’
UNION ALL
— このテーブルに対するインデックスのセグメント名
SELECT i.owner, i.index_name AS segment_name, s.segment_type
FROM dba_indexes i
JOIN dba_segments s ON i.owner = s.owner AND i.index_name = s.segment_name
WHERE i.table_owner = ‘YOUR_SCHEMA_NAME’ AND i.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘INDEX’
UNION ALL
— このテーブルに対するLOBセグメント名
SELECT l.owner, l.segment_name, s.segment_type
FROM dba_lobs l
JOIN dba_segments s ON l.owner = s.owner AND l.segment_name = s.segment_name
WHERE l.owner = ‘YOUR_SCHEMA_NAME’ AND l.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘LOBSEGMENT’
UNION ALL
— このテーブルに対するLOBインデックスセグメント名
— LOBインデックス名はDBA_LOBSのINDEX_NAME列から取得できる
SELECT l.owner, l.index_name AS segment_name, s.segment_type
FROM dba_lobs l
JOIN dba_segments s ON l.owner = s.owner AND l.index_name = s.segment_name
WHERE l.owner = ‘YOUR_SCHEMA_NAME’ AND l.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘LOBINDEX’
)
SELECT
trs.owner,
trs.segment_name, — 関連セグメントの名前
trs.segment_type, — 関連セグメントのタイプ
s.bytes, — 各セグメントのサイズ
ROUND(s.bytes / (1024*1024), 2) AS size_mb — MB単位
FROM
TableRelatedSegments trs
JOIN
dba_segments s ON trs.owner = s.owner AND trs.segment_name = s.segment_name AND trs.segment_type = s.segment_type
ORDER BY
trs.owner, trs.segment_type, trs.segment_name;
— 上記の関連セグメントの合計サイズを計算する場合
WITH TableRelatedSegments AS (
— テーブル本体のセグメント名
SELECT owner, segment_name, segment_type
FROM dba_segments
WHERE owner = ‘YOUR_SCHEMA_NAME’ AND segment_name = ‘YOUR_TABLE_NAME’ AND segment_type = ‘TABLE’
UNION ALL
— このテーブルに対するインデックスのセグメント名
SELECT i.owner, i.index_name AS segment_name, s.segment_type
FROM dba_indexes i
JOIN dba_segments s ON i.owner = s.owner AND i.index_name = s.segment_name
WHERE i.table_owner = ‘YOUR_SCHEMA_NAME’ AND i.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘INDEX’
UNION ALL
— このテーブルに対するLOBセグメント名
SELECT l.owner, l.segment_name, s.segment_type
FROM dba_lobs l
JOIN dba_segments s ON l.owner = s.owner AND l.segment_name = s.segment_name
WHERE l.owner = ‘YOUR_SCHEMA_NAME’ AND l.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘LOBSEGMENT’
UNION ALL
— このテーブルに対するLOBインデックスセグメント名
SELECT l.owner, l.index_name AS segment_name, s.segment_type
FROM dba_lobs l
JOIN dba_segments s ON l.owner = s.owner AND l.index_name = s.segment_name
WHERE l.owner = ‘YOUR_SCHEMA_NAME’ AND l.table_name = ‘YOUR_TABLE_NAME’ AND s.segment_type = ‘LOBINDEX’
)
SELECT
SUM(s.bytes) AS total_bytes,
ROUND(SUM(s.bytes) / (10241024), 2) AS total_size_mb,
ROUND(SUM(s.bytes) / (102410241024), 2) AS total_size_gb
FROM
TableRelatedSegments trs
JOIN
dba_segments s ON trs.owner = s.owner AND trs.segment_name = s.segment_name AND trs.segment_type = s.segment_type;
``TableRelatedSegments
この複雑なクエリは、CTEでテーブル本体、関連インデックス、関連LOBセグメント、関連LOBインデックスのセグメント名を全て抽出し、その後DBA_SEGMENTS` と結合してそれぞれのサイズを取得、最後に合計しています。これが、特定のテーブルがその関連オブジェクトを含めて使用しているディスク上の実サイズ*を把握する最も正確な方法の一つです。
3. スキーマ内の全テーブルのサイズを本体のみ集計する
特定のスキーマ内で、各テーブル本体がどれくらいのサイズかを確認したい場合に便利です。
sql
SELECT
s.owner,
s.segment_name AS table_name,
s.tablespace_name,
s.bytes,
ROUND(s.bytes / (1024*1024), 2) AS size_mb
FROM
dba_segments s
WHERE
s.segment_type = 'TABLE'
AND s.owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
ORDER BY
s.bytes DESC; -- サイズが大きい順に表示
このクエリは、指定したスキーマ内のすべてのテーブル本体セグメントのサイズをリストアップします。
4. スキーマ内の全テーブルについて、テーブル本体とインデックスの合計サイズを集計する
スキーマ内の各テーブルが、その本体とインデックスを合わせた合計でどれくらいのサイズを使用しているかを確認します。LOBセグメントやLOBインデックスは含まれません。
sql
-- DBA_TABLES と DBA_INDEXES を基に関連セグメントを特定し、DBA_SEGMENTS でサイズを取得して集計
SELECT
t.owner,
t.table_name,
SUM(s.bytes) AS total_size_bytes,
ROUND(SUM(s.bytes) / (1024*1024), 2) AS total_size_mb,
ROUND(SUM(s.bytes) / (1024*1024*1024), 2) AS total_size_gb
FROM
dba_tables t
JOIN
dba_segments s ON t.owner = s.owner
WHERE
t.owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
AND (
-- テーブル本体のセグメント
(s.segment_type = 'TABLE' AND s.segment_name = t.table_name)
-- このテーブルに対するインデックスのセグメント
OR (s.segment_type = 'INDEX' AND s.segment_name IN (SELECT index_name FROM dba_indexes i WHERE i.owner = t.owner AND i.table_name = t.table_name))
-- 注: このクエリでは LOB セグメント、LOB インデックスは含まれていません。
-- それらを含める場合は、前述の単一テーブル向けCTEクエリのように LOB 関連ビューとの結合/UNIONが必要です。
)
GROUP BY
t.owner,
t.table_name
ORDER BY
total_size_bytes DESC; -- 合計サイズが大きい順に表示
このクエリは、指定したスキーマ内の各テーブルについて、テーブル本体セグメントと、そのテーブルに属するすべてのインデックスセグメントのサイズを合計して表示します。より完全な合計サイズが必要な場合は、LOBセグメントやLOBインデックスも集計に含めるように修正する必要があります(前述の単一テーブル向けCTEクエリのロジックを応用)。
5. スキーマ内の全オブジェクトタイプ別の合計サイズ
特定のスキーマで、どのオブジェクトタイプ(テーブル、インデックス、LOBなど)が最も容量を消費しているかを確認します。
sql
SELECT
owner,
segment_type,
SUM(bytes) AS total_size_bytes,
ROUND(SUM(bytes) / (1024*1024), 2) AS total_size_mb,
ROUND(SUM(bytes) / (1024*1024*1024), 2) AS total_size_gb,
COUNT(*) AS object_count
FROM
dba_segments
WHERE
owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
GROUP BY
owner,
segment_type
ORDER BY
total_size_bytes DESC; -- 合計サイズが大きい順に表示
このクエリは、指定したスキーマ内の各セグメントタイプ(TABLE, INDEX, LOBSEGMENTなど)ごとに、使用している合計サイズとオブジェクト数を集計します。これにより、容量を最も圧迫しているオブジェクトの種類を特定できます。
6. 表領域ごとの合計サイズと空き容量(補足)
テーブルサイズそのものではありませんが、関連情報として、表領域の使用状況を確認するクエリも紹介します。これは、特定の表領域が満杯に近づいていないか、どの表領域が容量を多く使っているかを知るために非常に重要です。
使用済みの領域はDBA_SEGMENTSから、空き領域はDBA_FREE_SPACEから取得し、データファイルの総容量はDBA_DATA_FILESから取得して計算します。
sql
-- 表領域ごとの合計容量、使用済み容量、空き容量、使用率
SELECT
fs.tablespace_name,
df.total_bytes, -- 表領域の合計容量(バイト)
fs.free_bytes, -- 表領域の空き容量(バイト)
df.total_bytes - fs.free_bytes AS used_bytes, -- 表領域の使用済み容量(バイト)
ROUND((df.total_bytes - fs.free_bytes) / (1024*1024*1024), 2) AS used_gb, -- 使用済み容量(GB)
ROUND(fs.free_bytes / (1024*1024*1024), 2) AS free_gb, -- 空き容量(GB)
ROUND(df.total_bytes / (1024*1024*1024), 2) AS total_gb, -- 合計容量(GB)
ROUND((df.total_bytes - fs.free_bytes) / df.total_bytes * 100, 2) AS used_pct -- 使用率(%)
FROM
(SELECT tablespace_name, SUM(bytes) free_bytes FROM dba_free_space GROUP BY tablespace_name) fs, -- 表領域ごとの空き容量
(SELECT tablespace_name, SUM(bytes) total_bytes FROM dba_data_files GROUP BY tablespace_name) df -- 表領域ごとの合計データファイルサイズ
WHERE
fs.tablespace_name = df.tablespace_name
ORDER BY
used_bytes DESC; -- 使用済み容量が大きい順に表示
このクエリは、各表領域の全体のサイズ、使用済みのサイズ、空きサイズ、および使用率を表示します。テーブルサイズの確認と合わせて、表領域レベルでの容量管理を行う際に役立ちます。
7. 統計情報に基づくテーブル推定サイズ(全テーブル)
DBA_TABLESの統計情報(NUM_ROWS * AVG_ROW_LEN)を使って、全テーブルのおおよそのサイズを推定します。統計情報の鮮度に注意しながら参照してください。
sql
SELECT
owner,
table_name,
num_rows,
avg_row_len,
num_rows * avg_row_len AS estimated_bytes,
ROUND(num_rows * avg_row_len / (1024*1024), 2) AS estimated_size_mb,
last_analyzed -- 統計情報がいつ収集されたか
FROM
dba_tables
WHERE
num_rows IS NOT NULL -- 統計情報が存在する(行数がNULLでない)
AND avg_row_len IS NOT NULL -- 統計情報が存在する(平均行長がNULLでない)
AND owner NOT IN ('SYS', 'SYSTEM', 'OUTLN', 'DIP', 'ORACLE_OCM', 'DBSNMP', ...) -- システムスキーマを除外する場合
ORDER BY
estimated_bytes DESC; -- 推定サイズが大きい順に表示
システムスキーマのテーブルは通常運用でサイズ確認する必要性が低いため、WHERE句で除外することが多いです。この推定サイズはブロック内のオーバーヘッドや空き領域を考慮していないため、DBA_SEGMENTSに基づく実サイズよりも小さくなる傾向があります。あくまで「データ量」のおおよその目安として使用します。
パーティションテーブルのサイズ確認
大規模なテーブルは、管理性やパフォーマンス向上のためにパーティショニングされることがよくあります。パーティションテーブルの場合、テーブル全体としてのサイズだけでなく、個々のパーティションのサイズを確認することが重要になります。これは、データ増加が特定のパーティションに集中したり、古いパーティションのサイズを把握してアーカイブやパージを検討したりするためです。
パーティションテーブルのサイズ情報は、主に以下のビューから取得できます。
DBA_SEGMENTS: パーティションごとのセグメント情報が格納されています。PARTITION_NAME列でどのパーティションのセグメントか識別できます。DBA_TAB_PARTITIONS/ALL_TAB_PARTITIONS/USER_TAB_PARTITIONS: パーティションテーブルの各パーティションに関するメタ情報や統計情報(NUM_ROWS,AVG_ROW_LEN,LAST_ANALYZEDなど)が格納されています。
パーティションごとの実サイズを確認する (DBA_SEGMENTS)
DBA_SEGMENTSビューでは、PARTITION_NAME列が提供されます。パーティションテーブルのセグメントは、テーブル全体ではなくパーティションごとに作成されるため、この列で特定のパーティションのセグメントを識別できます。
sql
SELECT
s.owner,
s.segment_name AS table_name, -- パーティションテーブル名
s.partition_name, -- パーティション名
s.tablespace_name,
s.bytes,
ROUND(s.bytes / (1024*1024), 2) AS size_mb
FROM
dba_segments s
WHERE
s.segment_type = 'TABLE PARTITION' -- パーティションテーブルのセグメントタイプは 'TABLE PARTITION'
AND s.owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
AND s.segment_name = 'YOUR_TABLE_NAME' -- パーティションテーブル名を指定
ORDER BY
s.partition_name; -- パーティション名順に表示
このクエリは、指定したパーティションテーブルの各パーティション本体セグメントのサイズをリストアップします。インデックスがパーティション化されている場合(ローカルパーティションインデックス)、そのインデックスパーティションのサイズも同様に SEGMENT_TYPE = 'INDEX PARTITION' として DBA_SEGMENTS から取得できます。グローバルインデックスの場合はテーブル全体で一つのセグメントになります。
パーティションごとの統計情報に基づく推定サイズ (DBA_TAB_PARTITIONS)
DBA_TAB_PARTITIONSビューは、各パーティションの行数や平均行長といった統計情報を提供します。
sql
SELECT
owner,
table_name,
partition_name,
num_rows,
avg_row_len,
num_rows * avg_row_len AS estimated_bytes,
ROUND(num_rows * avg_row_len / (1024*1024), 2) AS estimated_size_mb,
last_analyzed -- パーティションの統計情報がいつ収集されたか
FROM
dba_tab_partitions
WHERE
owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
AND table_name = 'YOUR_TABLE_NAME' -- パーティションテーブル名を指定
AND num_rows IS NOT NULL
AND avg_row_len IS NOT NULL
ORDER BY
partition_name;
これも推定サイズですが、パーティション単位でのデータの増減傾向を把握するのに役立ちます。統計情報の鮮度には同様に注意が必要です。
パーティションテーブル全体の合計サイズ(本体+インデックス+LOB)
パーティションテーブル全体の合計サイズを確認するには、各パーティションセグメントと、関連するインデックスセグメント(ローカルインデックスパーティション、グローバルインデックスセグメント)、LOBセグメント(パーティション化されている場合)、LOBインデックスセグメント(パーティション化されている場合)を全て集計する必要があります。これは前述の単一テーブル向け合計サイズ算出クエリをパーティションに対応させたものです。
sql
-- パーティションテーブルに関連する全てのセグメント(本体、ローカル/グローバルインデックス、LOB)の合計サイズ
WITH PartitionTableSegments AS (
-- テーブル本体のパーティションセグメント
SELECT owner, segment_name AS table_name, partition_name, segment_type
FROM dba_segments
WHERE owner = 'YOUR_SCHEMA_NAME' AND segment_name = 'YOUR_TABLE_NAME' AND segment_type = 'TABLE PARTITION'
UNION ALL
-- このテーブルに対するローカルパーティションインデックスのセグメント
SELECT s.owner, s.segment_name AS index_name, s.partition_name, s.segment_type
FROM dba_segments s
JOIN dba_ind_partitions ip ON s.owner = ip.owner AND s.segment_name = ip.index_name AND s.partition_name = ip.partition_name
WHERE s.segment_type = 'INDEX PARTITION'
AND ip.index_owner = 'YOUR_SCHEMA_NAME' AND ip.table_name = 'YOUR_TABLE_NAME' -- 対象テーブルのローカルインデックス
UNION ALL
-- このテーブルに対するグローバルインデックスのセグメント (パーティションではない)
SELECT s.owner, s.segment_name AS index_name, NULL AS partition_name, s.segment_type
FROM dba_segments s
JOIN dba_indexes i ON s.owner = i.owner AND s.segment_name = i.index_name
WHERE s.segment_type = 'INDEX'
AND i.table_owner = 'YOUR_SCHEMA_NAME' AND i.table_name = 'YOUR_TABLE_NAME' -- 対象テーブルのグローバルインデックス
AND i.partitioned = 'NO' -- グローバルインデックス(非パーティション)
UNION ALL
-- このテーブルに対するLOBセグメント (パーティション化されている可能性あり)
SELECT s.owner, s.segment_name AS lob_segment_name, s.partition_name, s.segment_type
FROM dba_segments s
JOIN dba_lobs l ON s.owner = l.owner AND s.segment_name = l.segment_name
WHERE s.segment_type = 'LOBSEGMENT'
AND l.owner = 'YOUR_SCHEMA_NAME' AND l.table_name = 'YOUR_TABLE_NAME'
UNION ALL
-- このテーブルに対するLOBインデックスセグメント (パーティション化されている可能性あり)
SELECT s.owner, s.segment_name AS lob_index_name, s.partition_name, s.segment_type
FROM dba_segments s
JOIN dba_lobs l ON s.owner = l.owner AND s.index_name = l.index_name -- LOBインデックス名で結合
WHERE s.segment_type = 'LOBINDEX'
AND l.owner = 'YOUR_SCHEMA_NAME' AND l.table_name = 'YOUR_TABLE_NAME'
)
SELECT
SUM(s.bytes) AS total_size_bytes,
ROUND(SUM(s.bytes) / (1024*1024), 2) AS total_size_mb,
ROUND(SUM(s.bytes) / (1024*1024*1024), 2) AS total_size_gb
FROM
PartitionTableSegments pts
JOIN
dba_segments s ON pts.owner = s.owner AND pts.segment_name = s.segment_name
AND (pts.partition_name IS NULL OR pts.partition_name = s.partition_name) -- パーティション名がNULLでない場合は一致させる
AND pts.segment_type = s.segment_type;
このクエリはかなり複雑ですが、パーティションテーブルとその関連オブジェクト(ローカルインデックス、グローバルインデックス、LOBセグメント、LOBインデックス)のセグメントサイズを合計することで、正確なテーブル全体のサイズを算出します。
LOB列を含むテーブルのサイズ確認
CLOBやBLOBなどのLOB (Large Object) 列を含むテーブルは、そのデータがテーブル本体セグメントとは別のLOBセグメントに格納されることが一般的です。LOBセグメントは通常、対応するLOBインデックスセグメントを持ちます。テーブルの合計サイズを計算する際は、これらのLOBセグメントとLOBインデックスセグメントのサイズも含める必要があります。
LOB列に関する情報は、主に以下のビューから取得できます。
DBA_LOBS/ALL_LOBS/USER_LOBS: テーブルのどの列がLOBで、そのLOBデータの格納に使用されているLOBセグメント名とLOBインデックス名が示されます。
主要な列 (DBA_LOBS):
OWNER(VARCHAR2): LOB列を含むテーブルの所有者。TABLE_NAME(VARCHAR2): LOB列を含むテーブルの名前。COLUMN_NAME(VARCHAR2): LOB列の名前。SEGMENT_NAME(VARCHAR2): このLOB列のデータが格納されているLOBセグメントの名前。INDEX_NAME(VARCHAR2): このLOB列の管理に使用されるLOBインデックスの名前。TABLESPACE_NAME(VARCHAR2): LOBセグメントが格納されている表領域の名前。INDEX_TABLESPACE_NAME(VARCHAR2): LOBインデックスが格納されている表領域の名前。
DBA_SEGMENTS を DBA_LOBS と結合することで、LOBセグメントやLOBインデックスの実サイズを取得できます。これは前述の「特定のテーブルに関連する全てのセグメントの合計サイズ」を計算するクエリで既に示されていますが、LOBセグメント単体のサイズを確認するクエリも以下に示します。
特定のテーブルのLOBセグメントとLOBインデックスのサイズを確認する
sql
SELECT
l.owner,
l.table_name,
l.column_name,
l.segment_name AS lob_segment_name,
l.index_name AS lob_index_name,
s_lob.bytes AS lob_segment_bytes,
ROUND(s_lob.bytes / (1024*1024), 2) AS lob_segment_mb,
s_idx.bytes AS lob_index_bytes,
ROUND(s_idx.bytes / (1024*1024), 2) AS lob_index_mb
FROM
dba_lobs l
JOIN
dba_segments s_lob ON l.owner = s_lob.owner AND l.segment_name = s_lob.segment_name AND s_lob.segment_type = 'LOBSEGMENT'
JOIN
dba_segments s_idx ON l.owner = s_idx.owner AND l.index_name = s_idx.segment_name AND s_idx.segment_type = 'LOBINDEX'
WHERE
l.owner = 'YOUR_SCHEMA_NAME' -- スキーマ名を指定
AND l.table_name = 'YOUR_TABLE_NAME'; -- テーブル名を指定
このクエリは、指定したテーブルに含まれる各LOB列について、対応するLOBセグメントとLOBインデックスのサイズをそれぞれ表示します。LOBデータ自体のサイズはlob_segment_bytes、その管理構造であるLOBインデックスのサイズはlob_index_bytesで確認できます。
SQLクエリの詳細な解説と考慮事項
これまでに示したSQLクエリで使用されているテクニックや、サイズ確認を行う上での考慮事項について補足します。
サイズ単位の変換
DBA_SEGMENTSなどのビューで提供されるBYTES列はバイト単位です。人間が理解しやすいKB, MB, GB単位に変換するには、それぞれ1024, 10241024, 10241024*1024で割ります。ROUND()関数を使うと、小数点以下の桁数を指定して丸めることができます。
- KB:
bytes / 1024 - MB:
bytes / (1024 * 1024)またはbytes / POWER(1024, 2) - GB:
bytes / (1024 * 1024 * 1024)またはbytes / POWER(1024, 3)
クエリ例では、可読性のために1024*1024のように記述していますが、POWER(1024, 2)のように書いても同じです。
集計関数 (SUM, COUNT) と GROUP BY
複数のセグメントやオブジェクトの合計サイズを計算する場合や、特定の属性(スキーマ、セグメントタイプなど)ごとに集計する場合は、SUM()関数とGROUP BY句を使用します。COUNT(*)はグループ内の行数を数え、オブジェクト数などを把握するのに役立ちます。
WHERE 句によるフィルタリング
確認したいテーブルやスキーマを絞り込むために、WHERE句でOWNER, SEGMENT_NAME, TABLE_NAME, SEGMENT_TYPEなどの条件を指定します。ワイルドカード文字 (%, _) をLIKE演算子と組み合わせて使用すると、パターンマッチングによる検索が可能です(例: segment_name LIKE 'APP\_%' ESCAPE '\')。
CTE (Common Table Expressions)
複雑なクエリ、特に複数の異なる条件でセグメントを抽出し、それをまとめて処理する場合などに、CTE (WITH句で始まるサブクエリ) を使うとクエリの可読性が向上します。CTEは一時的な結果セットを定義し、その後のクエリで参照できます。前述の「特定のテーブルに関連する全てのセグメントの合計サイズ」を計算するクエリが良い例です。
パフォーマンスに関する考慮事項
DBA_SEGMENTS, DBA_TABLES, DBA_INDEXES, DBA_LOBSなどのビューは、データディクショナリという特殊な領域に格納されており、通常はパフォーマンスよくアクセスできるようにチューニングされています。しかし、これらのビューは非常に多くの行(データベース内の全オブジェクト数)を含む可能性があるため、大規模なデータベースに対してフィルタリングせずにクエリを実行したり、複雑なJOINを行ったりすると、時間がかかる場合があります。特に、スキーマ全体の集計を行うクエリでは、実行に時間がかかる可能性があります。
- 必ず
WHERE句で対象となるスキーマやテーブルを絞り込むようにしましょう。 - 頻繁に実行する必要がある場合は、結果を一時テーブルに格納したり、特定の集計を定期的に実行するジョブを作成したりすることを検討してください。
- オプティマイザが適切な実行計画を選択しているか、SQLトレースなどで確認することも有効です。
権限に関する考慮事項
DBA_ビューは、通常DBAロールやSELECT_CATALOG_ROLEを持つユーザーのみが参照できます。これらのビューへのアクセス権限がない場合は、代わりにALL_ビューやUSER_ビューを使用してください。ただし、ALL_やUSER_ビューは参照できる範囲が限られるため、データベース全体の容量管理などを行う場合は、DBA権限を持つユーザーで実行する必要があります。
統計情報の重要性と限界
DBA_TABLESやDBA_TAB_PARTITIONSに含まれるNUM_ROWSやAVG_ROW_LENといった統計情報は、テーブルのおおよそのデータ量を把握するのに役立ちますが、いくつかの重要な注意点があります。
- 鮮度: これらの統計情報は、
DBMS_STATSパッケージを使って明示的に収集されるか、自動統計収集ジョブによって収集されます。データが頻繁に更新、挿入、削除されるテーブルでは、統計情報はすぐに古くなり、実際の行数や平均行長と乖離します。LAST_ANALYZED列を確認して、統計情報の最終更新日時を常に把握してください。 - 推定値:
NUM_ROWS * AVG_ROW_LENは、あくまでデータ量から計算される推定サイズです。実際のディスク使用量には、ブロックヘッダー、行ディレクトリ、トランザクションスロット、PCT_FREEで予約された空き領域などのオーバーヘッドが含まれます。また、データの削除や更新によってできたブロック内の断片化された空き領域も、セグメントとしては割り当てられたままになっていることが多いため、推定サイズとDBA_SEGMENTSで示される実サイズには通常差があります。実サイズは推定サイズよりも大きくなる傾向があります。 - 使用用途: 統計情報に基づく推定サイズは、主にオプティマイザがSQLの実行計画を作成する際に使用されます。また、容量計画において「もし統計情報が最新であればこのくらいのサイズになるはず」という目安として使用することもできます。しかし、正確なディスク使用量を知りたい場合は、
DBA_SEGMENTSを参照する必要があります。
統計情報が古い場合は、DBMS_STATS.GATHER_TABLE_STATSプロシージャを実行して最新の統計情報を収集することを検討してください。
“`sql
— 特定のテーブルの統計情報を収集する
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => ‘YOUR_SCHEMA_NAME’, tabname => ‘YOUR_TABLE_NAME’, estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => DBMS_STATS.AUTO_DEGREE);
— スキーマ全体の統計情報を収集する
EXEC DBMS_STATS.GATHER_SCHEMA_STATS(ownname => ‘YOUR_SCHEMA_NAME’, estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE, degree => DBMS_STATS.AUTO_DEGREE);
“`
統計情報の収集はシステムリソースを消費するため、業務への影響が少ない時間帯に実行することが推奨されます。
その他の考慮事項
圧縮 (Compression)
Oracleには様々なデータ圧縮機能があります(BASIC, OLTP, ARCHIVE LOW/HIGHなど)。テーブルやパーティション、インデックスに圧縮が適用されている場合、DBA_SEGMENTSに表示されるBYTESは圧縮後のサイズを示します。DBA_TABLESビューのCOMPRESSION列とCOMPRESS_FOR列で、圧縮が有効になっているか、どのレベルの圧縮が使用されているかを確認できます。圧縮による容量削減効果は、圧縮前の論理的なデータ量(推定サイズ)と圧縮後の物理的なセグメントサイズを比較することで評価できます。
空き領域 (Free Space)
DBA_SEGMENTSのBYTES列は、セグメントに割り当てられている領域全体を示しますが、その領域の全てにデータが格納されているわけではありません。ブロック内のPCT_FREEで予約された領域、データの削除によってできた空き領域、エクステント内に未使用のブロックがある場合など、内部的な空き領域が存在します。DBA_TABLESのEMPTY_BLOCKS列は、割り当てられているが全くデータが含まれていないブロック数を示します。これらの内部的な空き領域を解放してOSに返すには、ALTER TABLE ... SHRINK SPACEコマンドなどを使用する必要があります(ただし制約事項や注意点があります)。
Oracleバージョンによる違い
本記事で紹介したビューやSQLクエリは、Oracle Database 11gR2以降のバージョンで広く利用可能ですが、Oracleのバージョンが古い場合や新しい機能(例: インメモリカラムストア、ブロックチェーンテーブルなど)に関する情報は、対応するビューや列が異なる場合があります。ご使用のOracleバージョルの公式ドキュメントを確認することをお勧めします。
テーブルサイズの監視とレポート
テーブルサイズの確認は一度きりではなく、定期的に行うことが重要です。特にデータ増加が著しいテーブルや、性能問題が疑われる大規模テーブルについては、サイズ推移を継続的に監視することで、問題の早期発見や将来予測が可能になります。
- 定期的な実行: 本記事で紹介したSQLクエリを、バッチスクリプトやOracle Schedulerジョブとして定期的に実行します。
- 履歴データの保存: 実行結果を別途履歴管理用のテーブルに保存します。これにより、時間の経過に伴うテーブルサイズの増加傾向を追跡できます。
- 閾値によるアラート: 特定のテーブルや表領域のサイズが事前に定義した閾値を超えた場合に、アラートを送信する仕組みを構築します。
- レポート作成: 収集した履歴データや最新情報を基に、定期的にレポートを作成し、関係者(DBA、開発者、システム管理者など)と共有します。
これにより、リアクティブな問題対応だけでなく、プロアクティブな容量管理やパフォーマンス改善活動が可能になります。
よくある間違いとトラブルシューティング
- 必要な権限がない:
DBA_ビューにアクセスするには通常DBA権限が必要です。「ORA-00942: table or view does not exist」などのエラーが出る場合は、権限が不足している可能性が高いです。ALL_ビューやUSER_ビューで代替するか、DBAに問い合わせてください。 - 統計情報が古い:
DBA_TABLESやDBA_TAB_PARTITIONSのNUM_ROWSやAVG_ROW_LENが最新でないと、推定サイズは不正確になります。LAST_ANALYZEDを確認し、必要であれば統計情報を収集してください。 - セグメントタイプを考慮していない: テーブル本体のサイズだけを確認すれば良いのか、それともインデックスやLOBなど関連する全てのオブジェクトを含めた合計サイズが必要なのか、目的に応じてクエリを使い分けてください。単に
DBA_SEGMENTS WHERE SEGMENT_TYPE = 'TABLE'とするだけでは、テーブル全体の使用領域を過小評価する可能性があります。 - パーティションを考慮していない: パーティションテーブルの場合、テーブル全体はセグメントを持たず、各パーティションがセグメントを持ちます。
DBA_SEGMENTSをSEGMENT_TYPE = 'TABLE PARTITION'でフィルタリングするか、DBA_TAB_PARTITIONSを使用してください。テーブル全体のサイズを合計するには、各パーティションのサイズを合計する必要があります。 - 単位変換の間違い: バイトからKB/MB/GBへの変換を正確に行ってください (1024ベース)。
- 大規模データベースでのパフォーマンス問題:
DBA_ビューへのクエリが遅い場合は、適切なフィルタリングを行うか、時間帯を考慮して実行してください。
まとめ
Oracleデータベースのテーブルサイズ確認は、適切な容量計画、パフォーマンスチューニング、ディスク領域管理のために不可欠な作業です。
- 最も正確な実サイズは、
DBA_SEGMENTSビューのBYTES列から取得できます。テーブル本体だけでなく、関連するインデックス、LOBセグメントなどのセグメントサイズを合計することで、テーブルが物理的に使用している総容量を把握できます。 - おおよその推定サイズは、
DBA_TABLESやDBA_TAB_PARTITIONSの統計情報(NUM_ROWS*AVG_ROW_LEN)から計算できます。これはデータ量のおおよその目安となりますが、統計情報の鮮度に強く依存します。 - パーティションテーブルの場合、各パーティションのサイズは
DBA_SEGMENTS(SEGMENT_TYPE = 'TABLE PARTITION') やDBA_TAB_PARTITIONSから確認します。テーブル全体のサイズは、全ての関連パーティションおよびグローバルオブジェクトのセグメントサイズの合計となります。 - LOB列を含むテーブルの場合、LOBデータは別のLOBセグメントに格納されます。
DBA_LOBSビューでLOBセグメント名を特定し、DBA_SEGMENTSからサイズを取得して合計サイズに含める必要があります。 - これらのビューを組み合わせて使用する際には、
SUM,GROUP BY,WHERE句、そして必要に応じてJOINやCTEを活用します。 - サイズの単位変換(バイトからMB/GBなど)は、
ROUND()と除算 (/) を使用して行います。 - サイズの確認は定期的に行い、履歴を管理することで、容量計画やデータ増加傾向の把握に役立てることができます。
本記事で紹介したSQLクエリとビューの詳細な説明が、皆様のOracleデータベース運用におけるテーブルサイズ管理の一助となれば幸いです。状況に応じて適切なクエリを選択し、データベースの状態を正確に把握してください。