본장의 목적은 블록에 대한 이해를 기반으로 오라클의 구조를 심도 깊게 이해하는 것이다. 본장에서는 테이블 및 인덱스 세그먼트를 구성하는 블록을 중점적으로 다룬다.
아래의6개의 테스트 케이스를 이용하여 FLM 방식의 동작원리를 알아보도록 하자.
– FLM 방식의 테이블 스페이스 생성
Create tablespace test_block
extent management local uniform size 1m
segment space management manual
datafile 'e:\oracle\product\10.2.0\oradata\hunny\test_block01.dbf' size 100m;
-- 해당 테이블스페이스에 테이블 생성
create table free_list_test(name char(1000))
tablespace test_block
pctfree 10
pctused 40;
– DBA_SEGMENTS 뷰를 조회하여 세그먼터 헤더 블록 주소 확인
select segment_name, header_file, header_block, blocks
from dba_segments
where segment_name = 'FREE_LIST_TEST';
SEGMENT_NAME HEADER_FILE HEADER_BLOC BLOCKS
---------------- ----------- ----------- -----------
FREE_LIST_TEST 5 9 128
1 rows selected.
테이블 세그먼트 헤드 블록 덤프 수행
*alter system dump datafile 5 block 9;*
Start dump data blocks tsn: 6 file#: 5 minblk 9 maxblk 9 buffer tsn: 6 rdba: _*0x01400009 (5/9)* --->DBA값은 5번째 파일의 9번째 블록 scn: 0x0000.007f902b seq: 0x01 flg: 0x00 tail: 0x902b1001 frmt: 0x02 chkval: 0x0000 type: 0x10=DATA SEGMENT HEADER - UNLIMITED --->블록 유형이 데이터 세그먼트 블록임을 나타냄(*아래Block Type 표참고) Hex dump of block: st=0, typ_found=1 Dump of memory from 0x0000000012D6A600 to 0x0000000012D6C600 Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140000a ext#: 0 blk#: 0 ext size: 127 --->아직 데이터가 입력되지 않은 상태 이므로 HWM는 0번 익스텐트의 0번째 블록을 가리킨다 #blocks in seg. hdr's freelists: 0 #blocks below: 0 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58922 flag: 0x40000000 Extent Map - 0x0140000a length: 127 ---> 사용가능한 블록의 시작 DBA는 0x0140000a이며 해당 익스텐트를 구성하는 블록의 개수는 127개 nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 0 ---> 1개의 프리리스트를 1개의 블록에서 관리하며 TFL은 현재 사용되지 않았음 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 ---> MFL를 나타내며 아직 사용되지않았음. End dump data blocks tsn: 6 file#: 5 minblk 9 maxblk 9 |
10진수 | 16진수 | 블록유형 |
---|---|---|
1 | 0x01 | Undo sement header |
11 | 0x0b | Data file header |
12 | 0x0c | Data segment header with FLG blocks |
14 | 0x0e | Unlimited undo segment header |
15 | 0x0f | Unlimited save undo segment header |
16 | 0x10 | Unlimited data segment header |
17 | 0x11 | Unlimited data segment header with FLS blocks |
18 | 0x12 | Extent map block |
23 | 0x17 | Bitmapped segment header |
29 | 0x1d | Bitmapped file space header |
32 | 0x20 | First level bitmap block |
33 | 0x21 | Second level bitmap block |
34 | 0x22 | Third level bitmap block |
35 | 0x23 | Pagetable segment header block |
36 | 0x24 | Pagetable extent map block |
37 | 0x25 | System Managed Undo Extent Map Blck |
-- 데이터를 입력 한 후 세그먼트 헤더 블록에 대한 덤프를 수행
begin
for I in 1..15 loop
insert into free_list_test values ('TEST' ||lpad(to_char(i),3,0));
commit;
end loop;
end;
/
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 9;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140000d ext#: 0 blk#: 3 ext size: 127 #blocks in seg. hdr's freelists: 1 --->프리블록을 관리하는데 사용 된 freelists가 1개로 증가 #blocks below: 3 ---> HWM아래에 3개의 블록 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58923 flag: 0x40000000 Extent Map - 0x0140000a length: 127 ---> 첫번째 익스텐트의 데이터 블록 시작 주소값 nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 3 SEG LST:: flg: USED lhd: 0x0140000c ltl: 0x0140000c --->프리리스트가 가리키는 프리블록의 DBA값=세번째 블록(아래12번블록)의 주소 값 End dump data blocks tsn: 6 file#: 5 minblk 9 maxblk 9 |
-- 각각의 블록에 저장된 레코드 수 확인
SQL> select dbms_rowid.rowid_block_number(rowid), count(*)
from free_list_test
group by dbms_rowid.rowid_block_number(rowid)
order by 1;
DBMS_ROWID. COUNT(*)
----------- -----------
10 7
11 7
12 1 ------->1개의 레코드, 추후 발생되는 입력작업은 여기에..
3 rows selected.
– TFL 확인하기 위해 DELETE 수행 후 TFL 정보확인
(테이블 생성 시 PCTUSED를 40으로 지정해서 생성했으므로 4건의 레코드를 첫 번째 블록에서 삭제하여 해당 TFL 변화 확인)
– 4건 삭제
delete free_list_test where name in ('TEST007','TEST006','TEST05','TEST04');
commit;
– DBMS_ROWID 패키지를 이용하여 블록 별 데이터 건수 확인
SQL> select dbms_rowid.rowid_block_number(rowid), count(*)
from free_list_test
group by dbms_rowid.rowid_block_number(rowid)
order by 1;
DBMS_ROWID. COUNT(*)
----------- -----------
10 3
11 7
12 1
3 rows selected.
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 9;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140000d ext#: 0 blk#: 3 ext size: 127 #blocks in seg. hdr's freelists: 2 --->프리블록을 관리하는데 사용 된 freelists가 2개로 증가 #blocks below: 3 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58923 flag: 0x40000000 Extent Map - 0x0140000a length: 127 nfl = 1, nfb = 1 typ = 1 nxf = 1 ccnt = 3 ---> nxf값(TFL의 개수)이 1로 증가 SEG LST:: flg: USED lhd: 0x0140000c ltl: 0x0140000c XCT LST:: flg: USED lhd: 0x0140000a ltl: 0x0140000a xid: 0x0001.01c.00000e20 --->DELETE작업에 의해 프리블록이발생, 이프리블록을 관리하기위해 TFL추가, lhd: 0x0140000a TFL에 의해 관리되는 프리블록의 시작주소 End dump data blocks tsn: 6 file#: 5 minblk 9 maxblk 9 |
위의 테스트에선 FREELISTS절을 지정하지 않았으므로 기본적으로 MFL,TFL만이 사용
-- 테스트 테이블 생성
create table free_list_test2(name char(1000))
storage(freelists 2)
tablespace test_block
pctfree 10
pctused 40;
– DBA_SEGMENTS 뷰를 조회하여 세그먼트 헤더블록 주소 확인
SQL> select segment_name, header_file, header_block, blocks
from dba_segments
where segment_name = 'FREE_LIST_TEST2';
SEGMENT_NAME HEADER_FILE HEADER_BLOC BLOCKS
--------------------------------- ------------------ ------------------- -----------
FREE_LIST_TEST2 5 137 128
1 rows selected.
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 137;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140008a ext#: 0 blk#: 0 ext size: 127 #blocks in seg. hdr's freelists: 0 #blocks below: 0 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58924 flag: 0x40000000 Extent Map - 0x0140008a length: 127 nfl = 2, nfb = 1 typ = 1 nxf = 0 ccnt = 0 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 ---> MFL SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 ---> PFL SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 ---> PLF End dump data blocks tsn: 6 file#: 5 minblk 137 maxblk 137 |
– PFL은 PID값을 이용하여 사용할 프리리스트를 정하게 됨
-- PID값 확인
SQL> select pid from v$process
where addr = (select paddr from v$session where sid = (select sid from v$mystat where rownum=1));
PID
-----------
22
1 rows selected.
-- 테스트 데이터 입력
begin
for I in 1..15 loop
insert into free_list_test2 values ('TEST' ||lpad(to_char(i),3,0));
commit;
end loop;
end;
/
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 137;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140008d ext#: 0 blk#: 3 ext size: 127 #blocks in seg. hdr's freelists: 1 #blocks below: 3 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58924 flag: 0x40000000 Extent Map - 0x0140008a length: 127 nfl = 2, nfb = 1 typ = 1 nxf = 0 ccnt = 0 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST:: flg: USED lhd: 0x0140008c ltl: 0x0140008c --->MFL을 제외한 2개의 PFL중 첫번째 PFL이 사용(mod(pid,freelists)+1) SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 End dump data blocks tsn: 6 file#: 5 minblk 137 maxblk 137 |
– PFL할당 공식
SQL> select mod(22,2) +1 as PFL_Number FROM dual;
PFL_NUMBER
----------
1
-- 다른 세션에서 데이터를 입력 할 경우 프리리스트의 사용변화 확인
PID = 19
-- 테스트 데이터 입력
begin
for I in 16..20 loop
insert into free_list_test2 values ('TEST' ||lpad(to_char(i),3,0));
commit;
end loop;
end;
/
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 137;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x0140008e ext#: 0 blk#: 4 ext size: 127 #blocks in seg. hdr's freelists: 2 --->프리블록을 관리하기위해 사용중인 freelists 개수 #blocks below: 4 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58924 flag: 0x40000000 Extent Map - 0x0140008a length: 127 nfl = 2, nfb = 1 typ = 1 nxf = 0 ccnt = 0 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 SEG LST:: flg: USED lhd: 0x0140008c ltl: 0x0140008c SEG LST:: flg: USED lhd: 0x0140008d ltl: 0x0140008d --->두번째 PFL을 사용 End dump data blocks tsn: 6 file#: 5 minblk 137 maxblk 137 |
SQL> select mod(19,2) +1 as PFL_Number FROM dual;
PFL_NUMBER
-----------
2
1 rows selected.
데이터 블록의 프리블록 여부는 블록 덤프를 통해서 확인이 가능
– DBA_SEGMENTS 뷰를 조회하여 세그먼트 헤더블록 주소 확인
SQL> select segment_name, header_file, header_block, blocks
from dba_segments
where segment_name = 'FREE_LIST_TEST2';
SEGMENT_NAME HEADER_FILE HEADER_BLOC BLOCKS
--------------------------------- ------------------ ------------------- -----------
FREE_LIST_TEST2 5 137 128
alter system dump datafile 5 block 138;
alter system dump datafile 5 block 139;
alter system dump datafile 5 block 140;
alter system dump datafile 5 block 141;
데이터 블록 덤프 수행(헤더부분만 요약)
Block header dump: 0x0140008a flg: - fsl: 0 fnx: 0x0 ver: 0x01 Block header dump: 0x0140008b flg: - fsl: 0 fnx: 0x0 ver: 0x01 Block header dump: 0x0140008c flg: O fsl: 0 fnx: 0x0 ver: 0x01 Block header dump: 0x0140008d flg: O fsl: 0 fnx: 0x0 ver: 0x01 |
– flg : 블록이 프리리스트에 등록된 블록인지의 여부를 나타내는 flag값 ( - : 프리블록아님 , O : 프리블록)
– fsl : Free Space Lock 해당블록이 Transaction Free List로 관리 될 경우 TFL의 개수를 나타냄
– fnx : 다음 프리블록에 대한 주소 값을 나타냄
-- 데이터 입력
begin
for I in 1..50 loop
insert into free_list_test2 values ('TEST' ||lpad(to_char(i),3,0));
commit;
end loop;
end;
/
SQL> select dbms_rowid.rowid_block_number(rowid), count(*)
from free_list_test2
group by dbms_rowid.rowid_block_number(rowid)
order by 1;
DBMS_ROWID. COUNT(*)
----------- -----------
138 7
139 7
140 7
141 7
142 7
143 7
144 7
145 1
8 rows selected.
-- 데이터 삭제
delete free_list_test2 where name in ('TEST003','TEST004','TEST005','TEST006','TEST007','TEST008','TEST009','TEST010','TEST011');
테이블 세그먼트 헤더 블록 덤프 수행
alter system dump datafile 5 block 137;
Extent Control Header - Extent Header:: spare1: 0 spare2: 0 #extents: 1 #blocks: 127 last map 0x00000000 #maps: 0 offset: 4128 Highwater:: 0x01400094 ext#: 0 blk#: 10 ext size: 127 #blocks in seg. hdr's freelists: 5 #blocks below: 10 mapblk 0x00000000 offset: 0 Unlocked Map Header:: next 0x00000000 #extents: 1 obj#: 58925 flag: 0x40000000 Extent Map - 0x0140008a length: 127 nfl = 2, nfb = 1 typ = 1 nxf = 2 ccnt = 0 SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 --->MFL SEG LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 --->PFL SEG LST:: flg: USED lhd: 0x01400091 ltl: 0x01400093 --->PFL에 의해 관리되는 블록 XCT LST:: flg: UNUSED lhd: 0x00000000 ltl: 0x00000000 xid: 0x0000.000.00000000{color:green} --->TFL{color} XCT LST:: flg: USED lhd: 0x0140008b ltl: 0x0140008a xid: 0x0007.01f.00000dee{color:green} --->TFL에의해 관리되는 블록{color} End dump data blocks tsn: 6 file#: 5 minblk 137 maxblk 137 |
alter system dump datafile 5 block 138;
alter system dump datafile 5 block 139;
alter system dump datafile 5 block 140;
alter system dump datafile 5 block 141;
alter system dump datafile 5 block 142;
alter system dump datafile 5 block 143;
alter system dump datafile 5 block 144;
alter system dump datafile 5 block 145;
데이터 블록 덤프 수행(헤더부분만 요약)
Block header dump: 0x0140008a flg: O fsl: 1 fnx: 0x0 --->다음 프리블록에 대한주소값:fnx: 0x0(없음) Block header dump: 0x0140008b flg: O fsl: 2 fnx: 0x140008a --->다음 프리블록에 대한주소값:fnx: 0x140008a Block header dump: 0x0140008c flg: - fsl: 0 fnx: 0x0 Block header dump: 0x0140008d flg: - fsl: 0 fnx: 0x0 Block header dump: 0x0140008e flg: - fsl: 0 fnx: 0x0 Block header dump: 0x0140008f flg: - fsl: 0 fnx: 0x0 Block header dump: 0x01400090 flg: - fsl: 0 fnx: 0x0 Block header dump: 0x01400091 flg: O fsl: 0 fnx: 0x1400092 |