1.はじめに
Oracleのデータ構造は、複雑なようでシンプルでもあるという印象を持っています。勉強しているときに覚えたことも、しばらくすると忘れてしまうことが私にはあります。
なので、学習した内容を細かくChatGPT先生に質問しながら、視覚的に分かりやすくして、明日の自分が覚えていられるようにまとめました。
2.領域一覧
ChatGPT先生(以下先生)に、「Oracleにある領域やプロセスを図にして~~~」と依頼したところ、以下の回答をもらいました。
先生の言うことなので正確だと思いますが、確認してみたところやはり正しいようです。
Oracle データベース全体
├── 表領域 (Tablespaces)
│ ├── データ表領域 (Data Tablespaces) - 必須
│ │ ├── データ・セグメント (Data Segments) - 必須
│ │ │ ├── エクステント (Extents) - 必須
│ │ │ │ ├── データブロック (Data Blocks) - 必須
│ ├── インデックス表領域 (Index Tablespaces) - 非必須
│ │ ├── インデックス・セグメント (Index Segments) - 必須(インデックス作成時)
│ │ │ ├── エクステント (Extents) - 必須
│ │ │ │ ├── データブロック (Data Blocks) - 必須
│ ├── 一時表領域 (Temporary Tablespaces) - 必須(一時データ用)
│ │ ├── 一時セグメント (Temporary Segments) - 必須(一時操作用)
│ │ │ ├── エクステント (Extents) - 必須
│ │ │ │ ├── データブロック (Data Blocks) - 必須
│ ├── UNDO 表領域 (Undo Tablespaces) - 必須
│ ├── UNDO セグメント (Undo Segments) - 必須
│ │ ├── エクステント (Extents) - 必須
│ │ │ ├── データブロック (Data Blocks) - 必須
├── 制御ファイル (Control Files) - 全体で一つまたは複数、必須
├── レド(リドゥ)ログファイル (Redo Log Files) - 全体で一つまたは複数、必須
└── データディクショナリ (Data Dictionary) - データベース全体に一つ、必須
というわけで、以下のファイルを理解する必要があります。それぞれについて[2-X]章で記載しています。特にエクステントとインデックスが難しかったので、先生と何十回もやり取りをして内容をまとめました。良い先生です。
- 表領域 (Tablespaces)
- データ・セグメント (Data Segments)
- エクステント (Extents)
- データブロック (Data Blocks)
- インデックス表領域 (Index Tablespaces)
- 一時表領域 (Temporary Tablespaces)
- UNDO セグメント (Undo Segments)
- 制御ファイル (Control Files)
- レド(リドゥ)ログファイル (Redo Log Files)
- データディクショナリ (Data Dictionary)
2-1 表領域 (Tablespaces)
実際のデータが格納されるファイルです。以下は実際のデータが格納されるファイルである表領域(Tablespaces)の作成と確認のSQL例です。
CREATE TABLESPACE users DATAFILE 'users01.dbf' SIZE 100M AUTOEXTEND ON NEXT 10M MAXSIZE UNLIMITED;
SELECT TABLESPACE_NAME, STATUS FROM DBA_TABLESPACES;
2-2 データ・セグメント (Data Segments)
具体的なデータオブジェクト(テーブルなど)が格納される場所です。
表領域の中に配置され、実際のデータが保存される領域です。以下は、テーブルを作成した時にデータセグメントが使用される例です。
表領域の中にデータセグメントのテーブルがある感じです。
CREATE TABLE employees (
id NUMBER PRIMARY KEY,
name VARCHAR2(100),
salary NUMBER
) TABLESPACE users;
SELECT OWNER, SEGMENT_NAME, SEGMENT_TYPE, TABLESPACE_NAME FROM DBA_SEGMENTS WHERE SEGMENT_TYPE = 'TABLE';
2-3 エクステント (Extents)
先生10ラリーくらいした箇所です。良い先生です。
- エクステントは、データセグメント(例えば、テーブルやインデックスなど)の一部であり、データが追加されると新しいエクステントが割り当てられる
- エクステントは連続したデータブロックの集合であり、データが分散せずに連続した領域に保存されるため、ディスクI/Oのパフォーマンスが向上する
- エクステントがないと、データベースはデータブロックを効率的に管理することができず、データがディスク上で散らばって保存されることになる
2-4 データブロック (Data Blocks)
Oracleデータベースの最小のデータ格納単位。複数並んで集まったものがエクステントになります。
2-5 インデックス表領域 (Index Tablespaces)
先生と何十回もラリーしました。良い先生です。
データ検索の効率化を行うための領域です。以下のデータが格納されます。
-
インデックスキー
内容: インデックスが作成される列の値。たとえば、employees テーブルの name 列にインデックスを作成した場合、その列の各値(例: 'Alice', 'Bob' など)がインデックスキーとして使われます。 -
ROWID
内容: 各インデックスキーに関連付けられた、テーブル内の対応する行を指し示す物理アドレスです。 -
ブランチブロック(Bツリーインデックスの場合)
インデックスの中間層を構成するブロックで、下層へのポインタ(次のブロックへのリンク)を含みます。 -
リーフブロック
インデックスの最下層を構成するブロックで、実際のインデックスキーとROWIDが格納されています。
検索プロセス:
以下のように検索されるため、リーフブロックを利用する分、全件検索より早くなります。
- ルートブロック: インデックスのルートブロックから検索を開始
- ブランチブロック1または2: 'Flank'はアルファベット順で後半にあるため、ルートブロックはブランチブロック2へのポインタを指す
- リーフブロック2: ブランチブロック2内で検索を続け、最終的にリーフブロック2に到達する。ここで、'Flank'というインデックスキーと対応するROWID(AAAC6F)が見つかりる
- データの取得: ROWIDを使用して、実際のテーブルから'Flank'の行データを迅速に取得する
- インデックスキーとROWIDの例
インデックスキー (Name) | ROWID |
---|---|
Alice | AAAC1A |
Bob | AAAC2B |
Charlie | AAAC3C |
Dave | AAAC4D |
Ellen | AAAC5E |
Frank | AAAC6F |
- ブランチブロック1
ブランチブロック1 | 子ブロックへのポインタ(リーフブロック) |
---|---|
Alice | リーフブロック1へのポインタ |
Bob | リーフブロック1へのポインタ |
Charlie | リーフブロック1へのポインタ |
- ブランチブロック2
ブランチブロック2 | 子ブロックへのポインタ(リーフブロック) |
---|---|
Dave | リーフブロック2へのポインタ |
Ellen | リーフブロック2へのポインタ |
Frank | リーフブロック2へのポインタ |
- リーフブロック
リーフブロック1 | インデックスキー (Name) | ROWID |
---|---|---|
Alice | Alice | AAAC1A |
Bob | Bob | AAAC2B |
Charlie | Charlie | AAAC3C |
リーフブロック2 | インデックスキー (Name) | ROWID |
---|---|---|
Dave | Dave | AAAC4D |
Ellen | Ellen | AAAC5E |
Frank | Frank | AAAC6F |
次に新しい従業員「Andrew」が追加された場合です。
インデックスに新しいインデックスキー「Andrew」が追加されます。Bツリーインデックスは常にソート順を保つため、新しいキーを適切な位置に挿入されます。
- ブランチブロック1の更新
ブランチブロック1 | 子ブロックへのポインタ(リーフブロック) |
---|---|
Alice | リーフブロック1へのポインタ |
Andrew | リーフブロック1へのポインタ |
Bob | リーフブロック1へのポインタ |
Charlie | リーフブロック1へのポインタ |
ブランチブロック2
ブランチブロック2 | 子ブロックへのポインタ(リーフブロック) |
---|---|
Dave | リーフブロック2へのポインタ |
Ellen | リーフブロック2へのポインタ |
Frank | リーフブロック2へのポインタ |
- リーフブロック1の更新
リーフブロック1 | インデックスキー (Name) | ROWID |
---|---|---|
Alice | Alice | AAAC1A |
Andrew | Andrew | AAAC1B |
Bob | Bob | AAAC2B |
Charlie | Charlie | AAAC3C |
- リーフブロック2
リーフブロック2 | インデックスキー (Name) ROWID |
---|---|
Dave | Dave |
Ellen | Ellen |
Frank | Frank |
2-6 一時表領域 (Temporary Tablespaces)
一時的なデータベース操作に使用されるデータを保存します。以下などが含まれます:
・ソートデータ: クエリ処理中の大量データのソート領域
・一時的なクエリ結果: 複雑なクエリからの中間結果
2-7 UNDO セグメント (Undo Segments)
UNDOセグメントは、データベース操作を取り消すために使用されるデータを格納されます。
-
INSERT文が実行された場合:
新しい行がテーブルに挿入されますが、UNDOセグメントにはその新しい行の削除情報が記録されます。
トランザクションをロールバックする際に、新しい行を削除するための情報が格納されます。 -
UPDATE文が実行された場合:
行のデータが更新されるが、UNDOセグメントには更新前の元のデータが記録されます。
トランザクションをロールバックする際に、行を元の状態に戻すための情報が格納されます。 -
DELETE文が実行された場合:
行がテーブルから削除されるますが、UNDOセグメントには削除された行の元のデータが記録されます。
トランザクションをロールバックする際に、削除された行を復元するための情報が格納されます。
SELECT SEGMENT_NAME FROM DBA_SEGMENTS WHERE SEGMENT_TYPE='UNDO';
2-8 制御ファイル (Control Files)
制御ファイルはデータベースの非常に重要なファイルで、データベースの構造に関する情報を含んでいます。具体的には、以下のような情報が含まれます。
- データベース名
- データベースが作成された日時
- データファイルとレドログファイルの場所とサイズ
2-9 レド(リドゥ)ログファイル (Redo Log Files)
データベースのすべての変更を記録し、障害時のリカバリに使用される。
-
INSERT文が実行された場合:
新しい行がテーブルに挿入されたことが記録されます。
REDOログには、この新しい行のデータが含まれます。 -
UPDATE文が実行された場合:
行のデータが更新されたことが記録されます。
REDOログには、更新後のデータが含まれます。 -
DELETE文が実行された場合:
行がテーブルから削除されたことが記録されます。
REDOログには、削除された行の識別情報が含まれます。
2-10 データディクショナリ (Data Dictionary)
データディクショナリは、データベースのメタデータを格納するシステムテーブルとビューの集合です。以下のような情報が含まれています:
- テーブル、ビュー、インデックスなどのオブジェクトの定義
- 各オブジェクトの権限やアクセス権
- データベースのスキーマ情報
おまけ
起動状態との関係性
-
NOMOUNT:
データベースのパラメータファイルのみが読み込まれまれる。 -
MOUNT:
制御ファイルが読み込まれ、データベースの構造に関するメタデータが確認される。
ALTER DATABASE MOUNT;
- OPEN:
データベースが利用可能になり、ユーザーがデータにアクセスできるようになります。
ALTER DATABASE OPEN;
データディクショナリ、各種セグメント、UNDOデータ、REDOログが活用されます。
- SHUTDOWN:
データベースを安全に終了させるために使用されます。
このプロセスでは、まずユーザートランザクションとサーバープロセスが終了され、次にバックグラウンドプロセスが停止し、最後にデータファイルとレドログファイルが閉じられます。
SHUTDOWN IMMEDIATE;