3章 Oracleの記憶域構造
本章では表領域の構造について書いていきます。
データベース記憶域構造については初級コースでもご紹介した内容となりますが、
本章ではより詳しい内容を書いていきたいと思います。
論理記憶域構造
Oracleは表領域という単位を使用して、データを管理しています。
テーブルなどのオブジェクトはその表領域に格納されます。
その表領域はより詳細な単位として分けられています。
データブロック
Oracleで使用する最小単位。OSブロックとマッピングされます。
DB_BLOCK_SIZE初期化パラメータで指定されており、DB作成後は変更不可。
デフォルトサイズは8KB。
エクステント
連続したデータブロックの集合。領域が足りなくなった場合に確保する領域の単位。
セグメント
複数のエクステントの集合。このエクステントの集合をセグメントと呼び、
セグメントは1つのオブジェクト(表、索引)に相当する。
表領域
複数のセグメントを格納する領域。表領域のタイプには永続、UNDO、一時があり、
永続は通常のセグメント、UNDOはUNDOデータ、一時は一時データを格納する。
データブロック
Oracleで扱う最小単位となり、データブロックに行のデータを格納します。
デフォルト8KBとなり、複数の行データを格納することができます。
データブロックの使用領域は以下の通りです。
・ブロック・ヘッダー:ディスクアドレス、セグメントタイプの情報
・表ディレクトリ:該当するブロックに行を格納する表情報
・行ディレクトリ:ブロックのデータ部分内の行の位置情報
・行データ:表に格納されるレコード
この空き領域はPCTFREEパラメータを使用して制御することができます。
PCTFREE指定の空き領域まで来ると、別の空いているデータブロックに格納します。
PCTFREEの指定はデフォルトで10%となりますが、行の更新が多い場合、
この数値を増やすことを検討します。
更新で現在格納されている値よりも大きいレコード長に更新した場合、
空き領域があれば、同じデータブロック内に更新データを格納しますが、
空き領域がない場合、別のデータブロックに行データを格納する為、
行データが通常1ブロックで収まるのが、複数レコードに格納されてしまいます。
これを
行連鎖と言い、データ取得効率が悪いデータの格納方法となってしまいます。
これを防ぐために空き領域はある程度確保する必要があります。
表領域の管理方法
セグメントの領域が足りなくなると、エクステント単位で領域を確保します。
このエクステントの管理は2つの方法があります。
・
ローカル管理 (推奨)
エクステントの管理をデータファイルヘッダーでビットマップを使用し管理します。
ビットマップはデータファイルごとに存在するため、負荷分散が行える為、
パフォーマンスが高い管理方法です。
表領域作成時に「EXTENT MANAGEMENT LOCAL」を指定すると
ローカル管理表領域になります。
・
ディクショナリ管理
データディクショナリにエクステントの管理情報を保持します。
1つのデータディクショナリを使用するため、更新が集中してしまい、
パフォーマンスはあまりよくありません。過去のバージョンでの管理方法です。
自動セグメント領域管理(ASSM)
セグメント領域管理とはデータブロックの領域管理のことです。
ローカル管理領域の場合、セグメント領域の管理方法は自動と手動があります。
手動は「空きリスト」という領域でブロックの空き領域を管理しています。
こちらは過去の管理方法であり、現在は自動を推奨しています。
自動セグメント領域管理(ASSM)とはビットマップを使用してデータブロックの
空き領域を自動で管理するため、以前とは違い特にブロックの空き領域を意識せずに
使用することが可能です。
データブロックの空き領域はビットマップで75%以上、50〜75%の間、
25〜50%の間、または25%以下で判断しています。
表領域作成時に「SEGMENT SPACE MANAGEMENT AUTO」を指定すると、
自動セグメント領域管理が有効になります。
表領域の作成
では表領域の作成構文を確認していきましょう。
[構文] 表領域の作成
CREATE TABLESPACE 表領域名
DATAFILE データファイル名 SIZE サイズ
[ EXTENT MANAGEMENT LOCAL UNIFORM SIZE XX | AUTOALLOCATE ]
[ SEGMENT SPACE MANAGEMENT MANUAL | AUTO ];
※構文は一部を抜粋しています。
「EXTENT MANAGEMENT LOCAL」句で表領域をローカル管理にできます。
UNIFORM SIZEはエクステント割り当て時のサイズを指定できます。
デフォルトは1MBとなります。
AUTOALLOCATEはOracleが自動的にサイズを割り当てます。
では実際に作成してみましょう。
SQL> CREATE TABLESPACE LOCAL_TBS
2 DATAFILE '/u01/app/oracle/oradata/orcl/local_tbs.dbf' SIZE 50M
3 EXTENT MANAGEMENT LOCAL UNIFORM SIZE 1M
4 SEGMENT SPACE MANAGEMENT AUTO;
Tablespace created.
SQL> SELECT tablespace_name,extent_management,allocation_type,
2 next_extent,segment_space_management
3 FROM dba_tablespaces
4 WHERE tablespace_name = 'LOCAL_TBS';
TABLESPACE_NAME EXTENT_MAN ALLOCATIO NEXT_EXTENT SEGMEN
------------------------------ ---------- --------- ----------- ------
LOCAL_TBS LOCAL UNIFORM 1048576 AUTO
作成した表領域情報を確認するには「DBA_TABLESPACES」データディクショナリ
で確認できます。
セグメントアドバイザ
セグメントアドバイザはセグメントが断片化しているかどうかを分析するツールです。
表(セグメント)にINSERTとDELETEが繰り返されると、データは断片化していくことがあります。
基本的にOracleはINSERT時に空き領域を探して格納する為、表の断片化は起こりにくい構造となっていますが、
索引は動作の仕様上、断片化が発生しやすくなります。
これらのセグメントが断片化されると、無駄に領域を使用するだけでなく、
SELECT文のパフォーマンスが悪くなる可能性があります。
では断片化の解消方法ですが、以下の方法でセグメントの断片化の解消が可能です。
・セグメントのSHRINK実施
・データのエクスポート/インポート
SHRINKコマンドで格納されているデータを再編成することができます。
SHRINKコマンドを実施するには「
行移動の有効化」が必要です。
[構文] 表の再編成
SQL> ALTER TABLE スキーマ名.表名 SHRINK SPACE;
では実際に行ってみましょう。
SQL> ALTER TABLE ora.employees SHRINK SPACE;
ALTER TABLE ora.employees SHRINK SPACE
*
ERROR at line 1:
ORA-10636: ROW MOVEMENT is not enabled
SQL> SELECT table_name,row_movement FROM dba_tables
2 WHERE owner = 'ORA' AND table_name = 'EMPLOYEES';
TABLE_NAME ROW_MOVE
-------------------- --------
EMPLOYEES DISABLED
上記の様に行移動を有効しておかないと、ORAエラーが発生します。
再編成時に再度レコードを入れ替えるため、ROWIDが変更されます。
デフォルトではROWIDは変更されないようになっている為、エラーとなります。
行移動の有効化を行うと、ROWIDの変更が可能となり、再編成が可能になります。
では行移動の有効化を行った後で、再度SHRINKを実行してみます。
SQL> ALTER TABLE ora.employees ENABLE ROW MOVEMENT;
Table altered.
SQL> SELECT table_name,row_movement FROM dba_tables
2 WHERE owner = 'ORA' AND table_name = 'EMPLOYEES';
TABLE_NAME ROW_MOVE
-------------------- --------
EMPLOYEES ENABLED
SQL> ALTER TABLE ora.employees SHRINK SPACE;
Table altered.
また断片化されているかどうかを調べるためにはセグメントアドバイザを使用します。
セグメントアドバイザはオプションは不要で使用可能な機能です。
セグメントアドバイザの実行はEntepriseManagerもしくはDBMSパッケージを使用して実行できます。
今回はセグメントアドバイザをDBMSパッケージで実行してみます。
SQL> variable id number;
SQL> begin
2 declare
3 name varchar2(100);
4 descr varchar2(500);
5 obj_id number;
6 begin
7 name:='Manual_Employees';
8 descr:='Segment Advisor Example';
9
10 dbms_advisor.create_task (
11 advisor_name => 'Segment Advisor',
12 task_id => :id,
13 task_name => name,
14 task_desc => descr);
15
16 dbms_advisor.create_object (
17 task_name => name,
18 object_type => 'TABLE',
19 attr1 => 'ORA',
20 attr2 => 'EMPLOYEES',
21 attr3 => NULL,
22 attr4 => NULL,
23 attr5 => NULL,
24 object_id => obj_id);
25
26 dbms_advisor.set_task_parameter(
27 task_name => name,
28 parameter => 'recommend_all',
29 value => 'TRUE');
30
31 dbms_advisor.execute_task(name);
32 end;
33 end;
34 /
PL/SQL procedure successfully completed.
上記で実施できました。結果は以下のコマンドで確認します。
SQL> select task_name, status from dba_advisor_tasks
2 where task_name = 'Manual_Employees';
TASK_NAME STATUS
------------------------------ -----------
Manual_Employees COMPLETED
SQL> select af.task_name,ao.attr2 segname,ao.type,af.message,af.more_info
3> from dba_advisor_findings af, dba_advisor_objects ao
4> where af.task_name = 'Manual_Employees';
TASK_NAME SEGNAME MESSAGE
----------------- ---------- -----------------------------------------------
Manual_Employees EMPLOYEES The free space in the object is less than 10MB.
Allocated Space:65536: Used Space:2290: Reclaimable Space :63246:
今回の結果では「このオブジェクトの空き領域は10MB以下です。」
割り当てサイズは64KB,使用領域は2290Bとのことでした。
いかがでしたでしょうか。初級よりも少し細かい部分をご紹介していきました。