h1.세그먼트 개요
오라클은 세그먼트라는 개념을 이용해 데이터베이스 공간(Space)를 관리한다.

  • 세그먼트는 테이블, 인덱스, 언두, LOB등 오라클이 제공하는 모든 종류의ㅡ 논리적인 공간을 말한다.
  • 세그먼트 -> 익스텐트 -> 블록(Block)
  • 오라클이 익스텐트에 의해 신규로 할당된 모든 공간을 다 실제로 사용중인 것은 아니기 대문에, 사용된 공간과 아직 사용되지 않은 공간을 구분하는 표식을 필요. HWM(High Water Mark)로 부른다. HWM은 세그먼트 헤더 블록에 그 정보가 저장된다.

세그먼트, 익스텐트, 블록, HWM의 개념 이해하기

  1. 현재 총 500 블록이 할당되어 있으며 모든 블록들을 사용 중인 테이블(세그먼트)에 1건의 로우를 추가로 Insert 한다고 하자.
  2. 사용 공간이 없으므로 프로세스는 익스텐트를 추가로 할당해야 한다. DMT(Dictionary Managed Tablespace)를 사용하는 경우에는 ST 락을 획득한 후에만 익스텐트를 할당 작업이 가능하다. ST락을 획득하는 과정에서 경합이 발생하면 enq:ST-contention 이벤트를 대기한다.
  3. ST락 경합은 오라클 9i 이후로는 거의 발생하지 않는다. 익스텐트가 추가로 할당되도 이에 따라 총 50블록(1 익스텐트 = 50 블록이라고 가정) 이 세그먼트에 추가된다. 50개 블록 중에서 오라클은 몇 개의 블록(여기서는 5개라고 가정)만을 포맷(Format)하고 사용가능공간으로 등록한다. 즉, 전체 550 블록 중
    Used Block = 500 + 5 = 505
    Unsed Block = 45
  4. HWM은 세그먼트의 전체 공간 중 사용가능 공간(포맷된 공간)과 미사용 공간(미 포맷 공간)을 구분하는 기준이 된다. 만일 추가로 계속해서 Insert가 이루어져서 포맷된 5개의 블록을 다 소진하게 되면 추가로 5개의 블록을 포맷하고 이를 사용가능공간으로 전환하고 HWM을 이동하게 된다. HWM을 이동하는 작업은 HW락을 통해 보호된다. HWM을 이동하고자 하는 프로세스는 반드시 세그먼트에 대해 HW락을 획득해야 한다. HW락을 획득하는 과정에서 경합이 발생하면 enq:HW - contention 이벤트를 대기한다.
  5. 동시에 여러 세션이 동일 세그먼트에 대해대량의 데이터를 추가하는 경우 잦은 HWM 이동에 의해 HW 락 경합 현상이 광범위하게 발생할 수 있다. HWM의 이동은 하나의 익스텐트가 모두 사용될 때까지 계속된다.

FLM(FreeList Management) - 수동 세그먼트 공간 관리

  • 오라클은 프리리스트(Freelist)라는 방법을 사용해서 세그먼트 공간을 관리
  • 프리리스트란 프리 블록을 링크드 리스트 형태로 관리하는 기법
  • 세그먼트 헤더 블록에서는 프리리스트의 머리 위치(Header)와 꼬리 위치(Tail)를 관리
  • 개별 데이터 블록에는 블록이 프리리스트에 존재하는지의 여부와 다음 프리 블록의 위치 정보를 가지고 있음
  • FLM을 사용하는 경우 프리 블록인지 아닌지의 여부는 테이블 생성 시 부여한 PCTFREE와 PCTUSED 속성에 의해 결정된다.
    예를 들어 PCTFREE = 10, PCTUSED=40인 경우, 블록 내에 데이터가 90% 이하까지 사용된 경우에는 프리 블록 상태이다.
    이후 90% 이상 사용되면 풀 블록(Full block)이 된다.
    다시 Delete나 Update에 의해 데이터가 줄어드는 경우 데이터양이 40%(PCTUSED)이하로 떨어지면 다시 프리 블록 상태가 된다.
  • 오라클은 기본적으로 세그먼트 별로 하나의 마스터 프리리스트(Master Freelist)를 할당하며 세그먼트 생성 시 FREELISTS 속성 값에
    할당된 수만큼 프로세스 프리리스트(Process Freelist)를 사용한다.
  • 만일 FREELISTS 속성 값을 1로 주면(Default=1), 마스터 프리리스트가 프로세스 프리리스트로 활용된다.
  • 익스텐트 할당에 따라 신규로 확보된 프리 블록들은 우선 마스터 프리리스트에 저장된다.
    프로세스 프리리스트가 실제로 사용되는 시점, 즉 개별 프로세스가 프리 블록을 필요로 하는 시점에 마스터 프리리스트로부터 필요한 수의 프리 블록을 얻어 온다.
  • 프로세스는 Insert 작업을 위해 프리 블록이 필요한 경우 자신에게 할당된 프로세스 프리리스트에 있는 블록을 사용하며,
    프리블록이 소진되면 마스터 프리리스트로부터 프리 블록을 다시 얻어온다.
  • 오라클은 간단한 해시 함수를 통해 프로세스를 프로세스 프리리스트에 할당한다.
  • 마스터 프리리스트에 더이상 프리 블록이 없으면 오라클은 HW 락을 획득하고 HWM을 이동해서 프리 블록을 확보하게 된다.
  • HWM을 이동하는 과정에 HW락 경합이 발생할 수 있으며, 이 경우 enq:HW - contention 이벤트를 대기한다.
  • 익스텐트에 할당된 블록이 모두 사용된 경우에는 이그텐트를 추가로 할당한다.
  • 만일 특정 트랜잭션이 Update나 Delete에 의해 기존에 풀(Full) 상태였던 블록을 프리 블록으로 바꾸게 되면
    트랜재견 프리리스트(Transaction Freelist)를 생성한다.
  • 트랜잭션 프리리스트는 트랜잭션에 의해 프리블록으로 변경된 블록들을 저장하며, 프로세스는 트랜잭션이
    유지되는 동안은 가능하면 트랜잭션 프리리스트를 사용한다. 사용이 끝난 프리 블록들은 이후 다시 마스터 프리리스테 반환한다.


프리리스트의 구조

  • 만일 세그먼트에 대해 트랜잭션을 유발하는 실제 프로세스의 개수에 비해 프로세스프리리스트 개수가 지나치게 작다면
    프리리스트에서의 경합이 발생하게 되고 이로 인해 buffer busy waits 이벤트를 대기하는 현상이 생길 수 있다.
    여러 프로세스가 동일 프리리스트로부터 동일 프리 블록을 받아서 사용하려고 하는 상황에서 buffer lock 경합이 발생하기 때문이다.
  • 프로세스 개수를 고려하여 freelists 속성값을 충분히 크게 지정해줌으로써 BUFFER LOCK 경합 문제를 해결할 수 있다.
  • 오라클은 익스텐트 할당 시 FREELISTS * _BUMP_HIGHWATER_MARK_COUNT 값만큼 HWM을 이동시킨다.
  • _BUMP_HIGHWATER_MARK_COUNT는 HWM의 이동 크기를 결정하는 히든 파라미터로 기본 값은 5이다.
    따라서 FREELISTS의 값이 1인 경우에는 5블록만큼 HWM을 이동하게 되고, 이것은 곧 HWM이 이동하는 경우
    5개의 블록이 프리 블록으로 활용된다는 것을 의미한다.
  • 많은 양의 Insert가 수행되면 빠른 속도로 프리 블록이 소진되어 그만큼 HWM의 이동이 자주 발생하게 된다.
    이런 이유로 세그먼트를 동시에 사용하는 프로세스의 개수에 비해 프로세스 프리리스트의 개수를 작게 설정할 경우
    HW락 경합에 의한 enq:HW - contention 비엔트에 대한 대기현상이 광범위하게 생길 수 있다.
  • Buffer lock 경합과 마찬가지로 HW락 경합에 의한 성능 문제 또한 FREELIST 속성 값을 충분히 크게 해서 프로세스
    프리리스트의 개수를 늘려줌으로써 해결 가능하다.
  • 오라클은 프리리스트 경합을 줄이기 위해 프리리스트 그룹(Freelist Group) 기능을 제공한다.
  • 하나의 프리리스트 그룹은 독립적인 마스터 프리리스트와 프로세스 프리리스트를 가지며, 하나의 프리리스트 그룹은 독립적인 마스터
    프리리스트와 프로세스 프리리스트를 가지며, 하나의 세그먼트가 여러 개의 프리리스트 그룹을 포함한다.
  • RAC와 같은 멀티 인스턴스환경에서는 각 인스턴스별로 별도의 프리리스트 그룹을 사용함으로써 복수 개로 설정하면 오라클의
    세그먼트 헤더 블록과 별개로 프리리스트 그룹 블록을 세그먼트에 부여한다.
    따라서 프리리스트 그룹 기능을 사용하면 프리리스트 자체의 경합뿐만 아니라 세그먼트 헤더 블록에 대한 경합도 줄어듬

SQL> create tablespace flm_tbs
  2  datafile 'd:\oracle\product\10.2.0\oradata\ghlee\flm_tbs01.dbf' size 1m
  3  segment space management manual; --> FLM 사용

테이블스페이스가 생성되었습니다.

SQL> create table flm_tbl(id number)
  2  tablespace flm_tbs
  3  storage(freelists 1); --> 마스터 프리리스트만 사용

테이블이 생성되었습니다.

SQL> insert into flm_tbl values(1);

1 개의 행이 만들어졌습니다.

SQL> select segment_name, header_file, header_block from dba_segments
  2   where segment_name = 'FLM_TBL';

SEGMENT_NA HEADER_FILE HEADER_BLOCK
---------- ----------- ------------
FLM_TBL              9            9

SQL> alter system dump datafile 9 block 9;

시스템이 변경되었습니다.

Start dump data blocks tsn: 10 file#: 9 minblk 9 maxblk 9
buffer tsn: 10 rdba: 0x02400009 (9/9)
scn: 0x0000.001b7ecd seq: 0x01 flg: 0x04 tail: 0x7ecd1001
frmt: 0x02 chkval: 0x394e type: 0x10=DATA SEGMENT HEADER - UNLIMITED
.....
Extent Control Header
-----------------------------------------------------------------
Extent Header:: spare1: 0      spare2: 0      #extents: 1      #blocks: 7     
                last map  0x00000000  #maps: 0      offset: 4128  
    Highwater::  0x0240000b  ext#: 0      blk#: 1      ext size: 7    <-- HWM 정보  
#blocks in seg. hdr's freelists: 1     
#blocks below: 1     
mapblk  0x00000000  offset: 0     
                 Unlocked
   Map Header:: next  0x00000000  #extents: 1    obj#: 56618  flag: 0x40000000
Extent Map
-----------------------------------------------------------------
 0x0240000a  length: 7     

nfl = 1, nfb = 1 typ = 1 nxf = 0 ccnt = 1
SEG LST:: flg: USED   lhd: 0x0240000a ltl: 0x0240000a 
<-- 마스터 프리리스트. lhd = Heaer of Freelist, ltl = Tail of FreeList
    세그먼트 헤더의 마스터 프리리스트는 프리리스트를 이루는 머리 블록(lhd)과 꼬리 블록(ltl)의
    위치 값을 가지고 있으며, 이 값을 이용해 프리리스트를 관리한다.
 
SQL> select dbms_utility.data_block_address_file(to_number('0240000a', 'XXXXXXXX')) as FILE_NO,
  2  dbms_utility.data_block_address_block(to_number('0240000a', 'XXXXXXXX')) as
 BLOCK_NO
  3  from dual;

   FILE_NO   BLOCK_NO
---------- ----------
         9         10 
         
* Block Dump
Start dump data blocks tsn: 10 file#: 9 minblk 10 maxblk 10
buffer tsn: 10 rdba: 0x0240000a (9/10)
scn: 0x0000.001b7ecd seq: 0x04 flg: 0x04 tail: 0x7ecd0604
frmt: 0x02 chkval: 0xdf2b type: 0x06=trans data
Hex dump of block: st=0, typ_found=1
.....
Block header dump:  0x0240000a
 Object id on Block? Y
 seg/obj: 0xdd2a  csc: 0x00.1b7eb1  itc: 2  flg: O  typ: 1 - DATA
     fsl: 0  fnx: 0x0 ver: 0x01 <-- 프리리스트 정보
 
 Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
0x01   0x0003.029.00000329  0x00802064.0223.3e  ----    1  fsc 0x0000.00000000
0x02   0x0000.000.00000000  0x00000000.0000.00  ----    0  fsc 0x0000.00000000
.....

--> 데이터 블록의 헤더정보에서 flg 값이 "0" 이면 프리 블록, 즉 프리리스트에 존재한다는 의미이다.
    만일 이 값이 "-" 이면 프리 블록이 아니라는 의미이다. fnx 값은 프리리스트상의 다음 프리 블록의 위치를 가리킨다.
    현재 블록이 프리리스트의 마지막(꼬리) 블록이므로 다음 프리 블록은 존재하지 않으며, 값은 0x0 이다.


ASSM(Automatic Segment Space Management) - 자동 모드의 세그먼트 공간 관리

  • ASSM(Automatic Segment Space Management)이 추가되면서 자동화된 공간 관리가 가능해 졌으며
    ASSM을 사용하면 프리리스트 속성을 지정할 필ㄹ요가 없으며 가 블록의 상태를 비트맵(Bitmap)값으로
    관리하는 블록들에 의해 공간관리가 자동화 된다.
  • ASSM을 사용할 경우 프리 블록에 대한 모든 정보들은 비트맵 블록에서 관리 된다.
  • 비트맵 블록들은 총 3단계 깊이의 트리로 관리된다.
    • 루트노드는 3rd level bmb (3레벨 비트맵 블록) 또는 L3 BMB
    • 브랜치 노드는 2nd level bmb (2레벨 비트맵 블록) 또는 L2 BMB
    • 리프 노드는 1st level bmb (1레벨 비트맵 블록) 또는 L1 BMB라고 부른다.
  • L3 BMB는 세그먼트 헤더 블록에 존재하며 L2 BMB들에 대한 포인터 역할을 한다.
  • L2 BMB는 다시 L1 BMB들에 대한 포인터 역할을 하며, 각 L1 BMB에 대한 간략한 정보도 함께 가지고 있다.
  • 하나의 L1 BMB는 DBA 범위(DBA Range)를 관리한다. DBA범위는 익스텐트 경계를 벗어나지 않는 연속된 블록들의 모임을 의미한다.
  • 세그먼트 크기에 따라 하나의 L1 BMB에서 작게는 16개에서, 많게는 1024개의 데이터 블록의 상태를 관리한다.
  • 데이터 블록의 여유 공간의 정도는 Full, Unformated, 0~25% free, 25~50% free, 50~75% free, 75~100% free의 6단계 등급으로 나뉜다.
  • Insert/Update/Delete에 의해 블록의 공간상태가 변경되면 L1 BMB의 정보가 변경된다. 프로세스에 의해 추가적인 공간이 요구되면
    오라클은 L1 BMB수를 늘리며, 필요 하다면 L2 BMB, L3 BMB도 추가적으로 할당한다.
  • 모든 블록의 여유 공간 정보가 비트맵 블록에서 관리되기 때문에 FLM에서와 같은 프리리스트 구조를 사용하지 않는다.
    또한 PCTUSED 속성은 더 이상 사용되지 않는다.


ASSM 구조

  • 포맷된(사용중인) 블록들 사이에 포맷되지 않은(미사용중인) 블록들이 존재한다.
    비트맵 블록들에 의해 프리 블록이 할당되는 방식으로 인해 HWM아래에 존재하는데도 불구하고 포맷되지 않은 상태의 블록들이 존재할 수 있다.
  • 익스텐트의 크기가 클 경우에는 하나의 익스텐트가 여러 개의 L1 BMB에 의해 나누어서 관리된다.
    따라서 익스텐트 영역 내에서도 아직 포맷이 이루어지지 않은 DBA 범위(DBA Range)와 포맷이 이루어진 DBA 범위로 나뉘게 된다.
  • 이런 이유로 assm에서는 하나의 세그먼트에 대해 두개의 HWM을 관리한다.
    • Low HWM(LHWM)이하의 블록들은 모두 포맷이 이루어진 상태임이 보장
    • High HWM(HHWM) 이상의 블록들은 모두 포맷되지 않은 상태이다.
    • LHWM과 HHWM 사이의 블록들은 일부는 포맷되고, 일부는 포맷되지 않은 상태이다.
  • ASSM을 사용하면 기본적으로 오라클에 의해 세그먼트 공간이 관리되기 때문에 DBA가 잘못된
    스토리지 속성(FREELISTS, FREELIST GROUPS등)을 부여함으로써 성능문제가 야기될 가능성이 근본적으로 없어진다.
  • 프리 블록들이 자연스럽게 분산되기 때문에 FLM에서의 프리리스트 경합과 같은 성능 문제가 나타나지 않는다.
  • 동시에 많은 프로세스가 프리 블록을 사용하면서 비트맵 블록 자체의 정보를 변경하게 되면 비트맵 블록에 대한
    UFFER LOCK 경합이 발생할 수 있다. 이경우 프로세스들은 buffer busy waits 이벤트를 대기한다.