ORACLE/TUNING2010. 2. 11. 21:18
반응형
서두


한마디로 스페이스 감시라고 해더라도, 그 목적 및 실현 수단은 여러가지입니다. 본장에서는 그 중에서도 이른바 「단편화」라고 하는 키워드에 주목해  단편화의 발생을 감시한다고 하는 관점에서 각종 스페이스 감시의 대상·방법에 대해 해설하겠습니다. 감시를 실시하고 문제를 밝혀낸 후, 그 문제를 해결하는 방법에 대해서는 다음 장인 제 6부에서 해설하겠습니다.이번은 SQL가 많이 소개됩니다만, 특별한 기술이 없는 한 SYSTEM 유저로 실행하고 있습니다.다른 유저로 실행하는 경우, 검색 대상의 딕쇼내리나 권한등을 적당 조정하면 된다. 덧붙여 본장으로 소개한 SQL는 실행 예의 형식이 되어 있으므로, SQL문을 재이용할 수 있도록 Code Tips에도 게재해 있습니다.
Code Tips



단편화란


Oracle에 있어서의 단편화란, Oracle의 물리 영역이 어떠한 형태로 불연속이 되어 있는 상태를 말합니다. 단편화가 발생하면 발생의 정도로 따라 주로 이하와 같은 영향이 발생한다.

  • 영역이 효율적으로 이용되지 않고, 실데이터량에 비해 보다큰 디스크 용량을 소비해 버린다.
  • I/O에 시간이 걸려, 퍼포먼스가 떨어진다.

한마디로 단편화 라고 해도 Oracle의 경우 DB의 물리 구조가 계층 구조가 되어 있어, 계층에 따라 나타나는 단편화의 현상에 차이가 있습니다.표 1으로 DB의 물리 구조에 대응한 단편화 현상을 정리했습니다. 앞으로 각각의 단편화 현상에 대하고 설명합니다. 단편화 현상의 해소 방법에 대해서는 제6회에서 정리해 해설하겠습니다.

 

표1:Oracle의 물루구조와 단편화
계층 단편화 대상
데이터파일 (테이블스페이스) ・파일 레벨의 단편화
・데이터 파일 레벨의 미사용 영역의 발생
세그먼트 ・위치(값)이 높은 하이 워터 마크
・세그먼트 레벨의 미사용 영역발생
・계층이깊은 인덱스
익스텐트 ・불연속 extent
블럭

・행 이행
・행 연쇄

블록내의 미사용 영역의 발생

 


◆ 제2장 데이터파일(데이블스페이스)레벨의 단편화


파일 레벨의 단편화


아무리 블록 레벨이나 세그먼트(segment) 레벨 등의 세세한 레벨로 단편화를 해소해도, 데이터 파일의 레벨로 단편화가 발생하고 있으면 별로 의미가 없습니다.특히 하나의 디스크에 데이타베이스가 깔려있고 게다가  초기의 물리 설계를 대충한 시스템에 대해선  격렬하게 단편화가 발생해 시스템의 퍼포먼스를 떨어뜨리고 있을 가능성이 있습니다.또, 테이블 스페이스의 설정으로 자동 확장을 하고 있었을 경우, 파일 레벨의 단편화가 일어나기 쉬워집니다. 파일 레벨의 단편화의 상황은 OS레벨의 이야기가 된다.  예를 들면 Windows라면 defrag 툴이라고 하는 OS의 기능이용한다.

 

High Water mark란


데이터 파일 레벨의 미사용 영역의 발생에 대해 설명하기전에 사전 지식으로서 하이 워터 마크(이하 HWM)에 대해 해설합니다. Oracle에 있어서의 HWM와는 과거에 데이터가 격납된 것이 있는 제일 높은(마지막) 위치를 나타내는 지표가 됩니다.하이 워터 마크의 개념은 데이터 파일과 세그먼트(segment)에 존재합니다.

 

그림1:high water mark의 개념



데이터 파일 레벨의 미사용 영역의 발생 HWM 이후의 미사용 영역


데이터 파일내의 미사용 영역은, HWM 이후의 미사용 영역 및 HWM 이전의 세그먼트(segment)간의 미사용 영역으로부터 구성됩니다.여기에서는 전자에 대해 언급하겠습니다.HWM 이후의 미사용 영역은 데이터의 검색이나 갱신에는 영향을 주지 않습니다만, 격납하고 있는 데이터 용량에 비교해 데이터 파일의 사이즈가 크기 때문에 실데이터량에 비교해 백업 및restore에 시간을 필요로 하게 됩니다.반면 앞으로의 데이터 파일의 확장을 막기 위해서 사전 확보하고 있는 경우도 있으므로 통틀어 HWM 이후의 미사용 영역이 큰 것이 나쁜 일이라고는 말할 수 없습니다.차후의 데이터의 증가 예상과의 균형으로 사이즈의 조정을 실시 한다.어느 테이블스페이스에 존재하는 데이터 파일의 HWM 이후의 미사용 영역의 합계에 관한 정보는 이하의 SQL로 파악하는 것이 가능합니다.

 

SQL>
select sumdf.file_name "Datafile 명",
  to_char(sumdf.total_bytes, 'FM999,999,999,990') "tablespace size",
  to_char(sumfs.free_bytes, 'FM999,999,999,990')
    "HWM이후 미사용 영역사이즈"
from (select df.file_id, df.file_name, sum(df.bytes) total_bytes
      from dba_data_files df
      where df.tablespace_name = upper('&&tsname')
      group by df.file_id, df.file_name) sumdf
left outer join (select fs.file_id, fs.bytes free_bytes
                 from (select fs2.file_id, fs2.bytes, fs2.block_id,
                         max(fs2.block_id) over (partition by
                         fs2.file_id) max_block
                       from dba_free_space fs2
                       where fs2.tablespace_name = upper('&&tsname')
                       ) fs
                 where fs.block_id = fs.max_block) sumfs
on (sumdf.file_id = sumfs.file_id);

 
tsname에 값을 입력하시오: USERS3
구6: where df.tablespace_name = upper('&&tsname')
신6: where df.tablespace_name = upper('USERS3')
구12: where fs2.tablespace_name = upper('&&tsname')) fs
신12: where fs2.tablespace_name = upper('USERS3')) fs
 
Datafile명
--------------------------------------------------------------------------------
tablespace size                              HWM이후 미사용 영역사이즈
-------------------------------- --------------------------------
D:\ORACLE\ORADATA\TEST1\USERS03.DBF
786,432,000                                 34,504,704

D:\ORACLE\ORADATA\TEST1\USERS03_2.ORA
134,217,728                                 133,464,064
 

상기 SQL의 실행에 있어서 tsname에는 테이블 스페이스명을 입력해 주세요.DBA_FREE_SAPCE 딕쇼내리의 각 데이터 파일마다로 블록 ID가 제일 큰 빈영역을 추출하고 있습니다. 

 

하는 김에 한 테이블 스페이스 전체의 미사용 영역을 요구하는 SQL도 게재해 보았습니다.

 

 tselect to_char(sumdf.total_bytes, 'FM999,999,999,990')
  "tablespace size",
  to_char(sumdf.total_bytes - sumfs.free_bytes, 'FM999,999,999,990')
  " 사용완료 영역 size",
  to_char(sumfs.free_bytes, 'FM999,999,999,990') "미사용영 역사이즈",
  to_char((nvl(sumfs.free_bytes, 0) / sumdf.total_bytes) * 100, 
  'FM990.99') || '%' " 사용율"
from (select df.tablespace_name, sum(df.bytes) total_bytes
      from dba_data_files df
      group by df.tablespace_name) sumdf
left outer join (select fs.tablespace_name, sum(fs.bytes) free_bytes
                 from dba_free_space fs
                 group by fs.tablespace_name) sumfs
on (sumdf.tablespace_name = sumfs.tablespace_name)
where sumdf.tablespace_name = upper('&tsname');
 
tsname에 값을 입력하시오: USERS3
旧 13: where sumdf.tablespace_name = upper('&tsname')
新13: where sumdf.tablespace_name = upper('USERS3')
 
tablespace size                            사용완료 영역 size
-------------------------------- --------------------------------
미사용영역사이즈                         사용율
-------------------------------- ----------------
920,649,728                               487,653,376
432,996,352                               47.03%
 

상기 SQL의 실행에 있어서 tsname에는 테이블 스페이스명을 입력해 주세요. 이쪽은 비어있는 영역 모두를 집계하고 있습니다.


데이터 파일 레벨의 미사용 영역의 발생 HWM 이전의 세그먼트(segment)간의 미사용 영역


데이터 파일내의 미사용 영역은, HWM 이후의 미사용 영역 및 HWM 이전의 세그먼트(segment)간의 미사용 영역으로부터 구성됩니다.여기에서는 후자에 대해 언급하겠습니다.
세그먼트(segment)간의 미사용 영역은 물리 단위에서는 extent가 됩니다.로컬 관리표 영역에서, 특히 UNIFORM 사이즈 지정의 경우는 이러한 영역도 효율적으로 이용됩니다만, AUTOALLOCATE 지정의 경우는 미사용인 채 남을 가능성이 있습니다.HWM 이전의 세그먼트(segment)간에 어느 정도의 미사용 extent가 존재하는지에 대해서는 이하의 SQL로 조사할 수 있습니다.

 

SQL>
select sumdf.file_name " 데이터 파일명",
  to_char(sumfs.free_bytes, 'FM999,999,999,990') "미사용영역사이즈"
from (select df.file_id, df.file_name from dba_data_files df
      where df.tablespace_name = upper('&&tsname')) sumdf
left outer join (select fs.file_id, fs.bytes free_bytes
                 from (select fs2.file_id, fs2.bytes, fs2.block_id,
                         max(fs2.block_id) over (partition by
                         fs2.file_id) max_block
                       from dba_free_space fs2
                       where fs2.tablespace_name = upper('&&tsname')
                      ) fs
                 where fs.block_id <> fs.max_block) sumfs
on (sumdf.file_id = sumfs.file_id);
 
tsname에 값을 입력하시오: USERS3
구4: where df.tablespace_name = upper('&&tsname')) sumdf
신4: where df.tablespace_name = upper('USERS3')) sumdf
구9: where fs2.tablespace_name = upper('&&tsname')) fs
신9: where fs2.tablespace_name = upper('USERS3')) fs
 
데이터 파일명                                                   미사용영역사이즈
-------------------------------------------- -----------------
D:\ORACLE\ORADATA\TEST1\USERS03.DBF             32,768
D:\ORACLE\ORADATA\TEST1\USERS03.DBF             16,384
D:\ORACLE\ORADATA\TEST1\USERS03.DBF             278,528
D:\ORACLE\ORADATA\TEST1\USERS03.DBF             32,768
D:\ORACLE\ORADATA\TEST1\USERS03.DBF             81,920
 
 .........(이하생략)

상기 SQL의 실행에 있어서  tsname에는 테이블 스페이스명 입력한다.이 결과 많은 행이 표시되었다고 해도, 세그먼트(segment)간의 미사용 영역의 수가 많은 것에 의해 퍼포먼스에 관한 영향은, 로컬 관리표 영역의 경우는 경미합니다.또, 백업이나 restore의 처리 시간에는 HWM 이후의 미사용 영역과 같이 영향을 줍니다.또 빈 영역의 수는 아니고 합계 사이즈가 많은 경우는, 자세한 것은 다음 번에 해설합니다만 데이터 파일의 축소의 효과가 작아져 버립니다.



◆ 제3장 세그먼트 레벨의 단편화


수위가 높은 하이 워터 마크


HWM가 어떠한 것일까에 대해서는 제2장으로 해설했습니다.단지, 제2장으로 해설하고 있지 않는 중요한 포인트가 한 개 있습니다.그것은, HWM는 자동에서는 결코 내려가지 않는다는 점입니다.구체적인 낮추는 방법은 다음 번에 설명합니다만  예를 들면 전건을 DELETE문으로 삭제했다고 해도, HWM의 위치는 그대로입니다.

그림2:DELETE로 움직이지 않는 하이 워터 마크

세그먼트 (segment) 레벨의 HWM는 주로
  • 전건검색
  • 다이렉트·로드/다이렉트·로드·인서트
에 영향을 줍니다.이하 구체적으로 해설합니다.

(1)HWM의 전건검색에 대한 영향
테이블이나 인덱스의 풀 스캔을 실행하는 경우, 실제의 스캔 범위는 테이블이나 인덱스 전체가 아니고, HWM의 위치까지를 스캔 합니다.이것에 의해 그림 3의 상부와 같이 실제로 용량을 확보하고 있는 사이즈에 비교해 데이터량이 적은 경우의 처리 시간을 단축하고 있습니다.그러나, HWM가 자동으로 내려갈리 없습니다. 그 때문에  일단 많이 데이터가 들어가 있는 상태로부터 대량 삭제가 있으면, 그림 3의 하부와 같이, 실제로는 데이터가 들어가 있지 않음에도 불구하고 HWM의 위치까지 스캔 해 버려, 실데이터량에 비교해 검색에 시간이 걸려 버립니다.

그림3:하이 워터 마크의 풀 스캔시의 영향

(2)HWM의 다이렉트 처리에 대한 영향
다이렉트·로드나 다이렉트·로드·인서트는 INSERT문에 의해 데이터를 삽입하는 것이 아니라, 먼저 블록에 저장된 포맷 이미지를 작성해, 그 블록 이미지를 직접 씁니다.그렇기 때문에 조금이라도 데이터가 들어가 있는 블록에는 쓸 수 없습니다. HWM 이후의 블록은 비어 있는 것이 보증되고 있기 때문에, 다이렉트 처리는 그림 4의 상부와 같이 HWM 이후의 블록에 데이터를 씁니다.이러한 처리에 의해 다이렉트 처리는 퍼포먼스를 확보하고 있습니다.덧붙여서 패러렐·다이렉트·로드 때는 HWM 이후의 extent로부터 씁니다. 만약 HWM 이전의 영역에 빈 곳이 많은 경우, 그림 4의 하부와 같이 세그먼트(segment)내에 큰 빈 영역이 생기게 됩니다.만약 이 테이블에 다이렉트 처리에 의한 데이터 삽입 밖에 없는 경우, 이 빈영역은 사용되지 않는채 남아 버립니다.

 
그림4:하이 워터 마크의 다이렉트 처리에의 영향

(3)HWM의 위치를 찾는 방법
HWM의 위치를 알려면  DBMS_SPACE 패키지에 있는 UNUSED_SPACE 프로시저를 이용합니다.이 프로시저를 이용하기 위해서는, ANALYZE 혹은 ANALYZE ANY 시스템 권한이 필요합니다. 다만 실제로 ANALYZE를 실시하는 것은 아니기 때문에, 룰 베이스로 운용하고 있는 시스템에서도 이용 가능합니다. 또 빈영역 관리를 프리 리스트가 아닌 자동 세그먼트(segment) 관리(ASSM)를 이용하고 있는 경우는, UNUSED_SPACE 프로시저말고 SPACE_USA GE프로시저를 이용하지 않으면 잘못된 결과가 되어 버립니다.다음의 UNUSED_SPACE 프로시저의 이용 예를 이용해 HWM의 위치가 어떻게 표현되는지를 설명합니다.
 
SQL>
SQL> set serveroutput on
SQL> declare
       v_total_blocks              number;
       v_total_bytes               number;
       v_unused_blocks             number;
       v_unused_bytes              number;
       v_last_used_extent_file_id  number;
       v_last_used_extent_block_id number;
       v_last_used_block           number;
     begin
        dbms_space.unused_space(upper('&uname'), upper('&sename'), '&stype',
        v_total_blocks, v_total_bytes, v_unused_blocks, v_unused_bytes, 
        v_last_used_extent_file_id, v_last_used_extent_block_id, v_last_used_block);
        dbms_output.put_line('HWM가 있는 데이터 파일의 ID          :'
          || to_char(v_last_used_extent_file_id, '9,999,990'));
        dbms_output.put_line('HWM가 있는 extent의 개시 블록 ID   :'
          || to_char(v_last_used_extent_block_id, '9,999,990'));
       dbms_output.put_line('HWM가 있는 블록의 위치                  :'
          || to_char(v_last_used_block, '9,999,990'));
     end;
     /

uname에 값을 입력해 주세요: SCOTT
sename에 값을 입력해 주세요: CUSTOMERS
stype에 값을 입력해 주세요: TABLE
구 10:   dbms_space.unused_space(upper('&uname'), upper('&sename'), '&stype',
신  10:   dbms_space.unused_space(upper('SCOTT'), upper('CUSTOMERS'), 'TABLE',
HWM가 있는 데이터 파일의 ID          :        11
HWM 가 있는 extent의 개시 블록 ID   :     1,033
HWM가 있는 블럭의 위치                 :         6

PL/SQL프로시져가 정상적으로 종료했습니다.

상기 SQL 스크립트의 실행에 있어서, uname에는 세그먼트(segment) 소유자명을, sename에는 세그먼트(segment)명을, stype에는 세그먼트(segment)의 타입(TABLE/TABLE PARTITION/TABLE SUBPARTITION/INDEX/INDEX PARTITION/INDEX SUBPARTITION/CLUSTER/LOB의 어느쪽이든)을 입력한다.

상기 SQL 스크립트의 행 결과를 설명하면「HWM가 있는 데이타 파일의 ID」는 프로시져의 V_LAST_USED_EXTENT_FILE_ID파라미터의 값이 됩니다. DBA_DATA_FILES 딕쇼내리의 FILE_ID열이 V_LAST_USED_EXTENT_FILE_ID파라미터와 일치하는 데이터 파일중에 HWM가 존재하는 것을 나타내고 있습니다
 
「HWM가 있는 extent의 개시 블록 ID」는, 프로시저의 V_LAST_USED_EXTENT_BLOCK_ID파라미터의 값이 됩니다.???_EXTENTS(이하???(은)는 DBA/ALL/USER의 어느것이든) 딕쇼내리의 FILE_ID열이 V_LAST_USED_EXTENT_FILE_ID와 같고, 한편 BLOCK_ID열이 V_LAST_USED_EXTENT_BLOCK_ID와 일치하는 익스텐트중에 HWM가 존재하는 것을 나타내고 있습니다.「HWM가 있는 블록의 위치」는, 프로시저의 V_LAST_USED_BLOCK 파라미터의 값이 됩니다.해당 extent의 V_LAST_USED_BLOCK 파라미터의 값번째의 블록에 HWM가 존재하는 것을 나타내고 있습니다.

 
그림5:하이 워터 마크의 위치


세 그먼트(segment) 레벨의 미사용 영역의 발생 HWM 이후의 미사용 영역

제2장의 데이터 파일의 HWM 이후의 미사용 영역과 같은 영향이 있습니다. HWM 이후의 미사용 영역은 이하와 같은 방법으로 조사할수 있다.

(1)DBMS_SPACE.UNUSED_SPACE프로시져의 사용
앞서 기술한 DBMS_SPACE.UNUSED_SPACE 프로시저를 이용하는 것으로 세그먼트(segment)의 HWM 이후의 미사용 영역의 크기를 계산할 수 있습니다. 아래의 샘플 스크립트를 참조해 주세요.
 
SQL> set serveroutput on
SQL> declare
        v_total_blocks              number;
        v_total_bytes               number;
        v_unused_blocks             number;
        v_unused_bytes              number;
        v_last_used_extent_file_id  number;
        v_last_used_extent_block_id number;
        v_last_used_block           number;
      begin
       dbms_space.unused_space(upper('&uname'), upper('&sename'), '&stype',
       v_total_blocks, v_total_bytes, v_unused_blocks, v_unused_bytes, 
       v_last_used_extent_file_id, v_last_used_extent_block_id, v_last_used_block);
      dbms_output.put_line('현세그먼트용량:'
        || to_char(v_total_bytes, '999,999,999,990') || ' バイト');
      dbms_output.put_line('소비용량    :'
        || to_char(v_total_bytes - v_unused_bytes, '999,999,999,990') || ' バイト');
      dbms_output.put_line('나머지용량   :'
        || to_char(v_unused_bytes, '999,999,999,990') || ' バイト');
      dbms_output.put_line('소비율     :         '
       || to_char((v_total_bytes - v_unused_bytes) / v_total_bytes * 100, '990.99') || ' %');
    end;
   /

uname에 값을 입력해 주세요: SCOTT
sename에 값을 입력해 주세요: CUSTOMERS
stype에 값을 입력해 주세요: TABLE
구10:   dbms_space.unused_space(upper('&uname'), upper('&sename'), '&stype',
신  10:   dbms_space.unused_space(upper('SCOTT'), upper('CUSTOMERS'), 'TABLE',
현세그먼트용량 :       9,437,184 바이트
소비용량     :       8,593,408 바이트
나머지용량   :         843,776  바이트
소비율       :           91.06 %

PL/SQL프로시져가 정상 종료하였습니다.
상 기 SQL의 실행에 있어서, uname에는 세그먼트(segment) 소유자명을, sname에는 세그먼트(segment)명을, stype에는 세그먼트(segment)의 타입(TABLE/TABLE PARTITION/TABLE SUBPARTITION/INDEX/INDEX PARTITION/INDEX SUBPARTITION/CLUSTER/LOB)을 입력한다.

(2)ANALYZE 실행 후 딕쇼내리를 참조한다
테이블의 경우는 ANALYZE를 실행한 후의???_TABLES 딕쇼내리의 BLOCKS와 EMPTY_BLOCKS의 값을 검색하는 것으로도 HWM 이후의 미사용 영역의 크기를 구할 수 있습니다.BLOCKS는 세그먼트(segment)내의 사용이 끝난 블록수, EMPTY_BLOCKS는 세그먼트(segment)내의 미사용 블록수(HWM 이후)를 나타냅니다.
 SQL> analyze table scott.customers compute statistics;

테이블이 분석되었습니다.

SQL>
         select to_char((blocks + empty_blocks) * 8192, 'FM999,999,999,990') as "테이블 용량",
      to_char(empty_blocks * 8192, 'FM999,999,999,990') as "남은용량"
      from dba_tables where owner = '&uname' and table_name = '&tname';

uname에 값을 입력해 주세요: SCOTT
tname에 값을 입력해 주세요: CUSTOMERS
구 3: from dba_tables where owner = '&uname' and table_name = '&tname'
신 3: from dba_tables where owner = 'SCOTT' and table_name = 'CUSTOMERS'

테이블 용량                      남은용량
----------------------- --------------------------------
9,428,992                           843,776

상기의 테이블의 사용량에 관해서 SQL의 실행에 있어서, uname에는 세그먼트(segment) 소유자명을, tname에는 테이블명을 입력한다.
이 방법에 의한 세그먼트(segment) 용량과 (1)의 DBMS_SPACE.UNUSED_SPACE 프로시저를 이용하는 방법에 따르는 세그먼트(segment) 용량의 1 블록분 (본시험대에서는, 블록 사이즈를 8,192바이트로 하고 있습니다)의 차이는, 세그먼트(segment) 헤더를 포함하는지 포함하지 않는지의 차이입니다.전자가 세그먼트(segment) 헤더를 포함한 크기가 되어 있습니다.


세그먼트(segment) 레벨의 미사용 영역의 발생 HWM 이전의 미사용 영역


HWM 이전의 미사용 영역의 영향은, 본장의 최초로 설명한 HWM의 해설을 참조. 계산방법은, 테이블만의 대응입니다만, 이하와 같은 SQL로 산출할 수 있습니다.

SQL> analyze table scott.customers compute statistics;

테이블이 분석되었습니다

SQL>
        select to_char(avg_space * blocks, 'FM999,999,999,999') "빈영역"
        from dba_tables where owner = '&uname' and table_name = '&tname';
uname 에 값을 입력해 주세요: SCOTT
tname에 값을 입력해 주세요: CUSTOMERS
구 2: from dba_tables where owner = '&uname' and table_name = '&tname'
신 2: from dba_tables where owner = 'SCOTT' and table_name = 'CUSTOMERS'

빈 영역
--------------------------------
595,264

상기의 테이블의 사용량에 관해서 SQL의 실행에 있어서 uname에는 세그먼트(segment) 소유자명을, tname에는 테이블명을 입력해 주세요.


계층이 깊은 인덱스


B*Tree 인덱스는 계층 구조로 되어 있습니다. 이 계층이 깊으면 검색에 시간이 걸리게 됩니다. 계층의 깊이는, 인덱스를 ANALYZE 한 뒤 INDEX_STATS 딕쇼내리의 HEIGHT열 내지는 ???_INDEXES 딕쇼내리의 BLEVEL열로 조사할 수 있습니다. 이러한 열의 값이 4이상의 경우는, 인덱스를 이용한 검색의 퍼포먼스에 영향이 있으므로 때문에 재편성을 검토 한다. 또한 INDEX_STATS 딕쇼내리를 검색하는 경우는, VALIDATE STRUCTURE 옵션 첨부로 ANALYZE 커멘드를 실행할 필요가 있습니다.



◆ 제4장 익스텐트 레벨의 단편화


불연속 익스텐트


어떤 세그먼트(segment)를 구성하는 extent가 연속해서 확보되어 있지 않아도 퍼포먼스에 거의 영향을 주지 않습니다. 단지 불연속의 extent간의 타세그먼트(segment)의 extent가 미사용 extent가 되었을 경우, 특히 딕쇼내리 관리표 영역에서 세그먼트(segment)마다 개별의 INITIAL/NEXT/PCTINCREASE를 지정해 있는 경우는 불필요 영역의 발생하기 쉬워집니다. 로컬 관리의 경우는 이러한 일이 일어나지 않도록 하는 것으로 특별히 감시할 필요는 없을 것입니다. 감시하고 싶은 경우는 이하와 같은 스크립트로 감시를 할 수 있습니다.

SQL> select ext2.extent_id "extent ID", ext2.file_id "file ID",
       ext2.block_id "개시블럭ID", ext2.blocks "블럭수",
       case when ext2.extent_id = 0 then '선두 EXTENT'
         when ext2.old_fid <> ext2.file_id then '데이터파일틀림'
  5      when ext2.old_blk_id <> ext2.block_id then '불연속EXTENT'
  6      else '연속EXTENT'
  7    end "단편화 상태"
  8  from (select ext1.extent_id, ext1.file_id, ext1.block_id, ext1.blocks,
  9    lag(ext1.file_id, 1) over (order by ext1.extent_id) old_fid,
10    lag(ext1.block_id, 1) over (order by ext1.extent_id) +
11      lag(ext1.blocks, 1) over (order by ext1.extent_id) old_blk_id
12    from dba_extents ext1
13    where ext1.owner = '&uname' and ext1.segment_name = '&sname') ext2;

uname에 값을 입력해 주세요: SCOTT
sname에 값을 입력해 주세요: C3
구 13:   where ext1.owner = '&uname' and ext1.segment_name = '&sname') ext2
신 13:   where ext1.owner = 'SCOTT' and ext1.segment_name = 'C3') ext2

extent ID   file ID    개시블럭ID  블럭수  단편화 상태
--------- ------- ---------- ------ --------------------------
             0         12            113          2 선두 EXTENT
             1         13             93          2 데이터파일틀림
             2         12            115          2 데이터파일틀림
             3         13             95          2 데이터파일틀림
             4         13             97          2 연속EXTENT
             5         13             99          2 연속EXTENT
             6         13            101          2 연속EXTENT
             7         12            119          2 데이터파일틀림
             8         12            123          2 불연속EXTENT
             9         12            125          2 연속EXTENT

10행이 선택되었습니다.
상기의 테이블의 사용량에 관해서 SQL의 실행에 있어서, sname에는 세그먼트(segment) 소유자명을, tname에는 테이블명을 입력해 주세요.


◆ 제5장 블록 레벨의 단편화

행 이행

어느 레코드에 대해서 갱신을 했을 때에, PCTFREE로 확보한 영역을 가지고 있더라고 원래 존재하고 있던 블록에 들어가지 않는 길이가 되어 버렸다고 해 봅시다. 이 경우 Oracle는 해당 레코드를 다른 블록에 격납합니다. 이 때, 원래의 블록에 새로운 격납처에의 포인터를 남깁니다.이러한 상태를 행 이행이라고 부릅니다. 행 이행이 발생하면 해당 레코드는 본래 1 블록에 들어가는 길이 임에도 불구하고 2 블록에 건너 격납됩니다. 즉 이 레코드에 액세스 하기 위해서는 2 블록 읽어들일 필요가 있는 것입니다.행 이행이 발생하고 있는 레코드에의 액세스가 많으면 읽기 I/O의 증가나 캐쉬 히트율의 저하라고 하는 영향이 발생합니다.

그림6:행 이행



행 연쇄


행 연쇄는 행 이행과 같이 레코드가 복수 블록에 걸치는 현상입니다만, 행 연쇄는 단지 블록에 격납 가능한 사이즈 이상의 레코드가 복수 블록에 건너 격납되는 현상입니다. 물리적으로 큰 레코드를 넣으려 하고 있는 이상 어쩔 수 없는 현상입니다만, 다발하면 행 이행과 같은 영향이 있습니다.

그림7:행 연쇄



행 이행·행 연쇄를 조사한다


행 이행과 행 연쇄는 같은 방법으로 조사합니다. 테이블을 ANALYZE 한 후,???_TABLES 딕쇼내리의 CHAIN_CNT열에 행 이행내지 행 연쇄하고 있는 레코드수가 격납됩니다. 즉, 행 이행과 행 연쇄는 따로 따로 파악할 수 없습니다.



블록 레벨의 미사용 영역의 발생


본쳅터 이전에 문제가 발생하고 있지 않는데 세그먼트(segment) 용량에 비교해 격납 가능한 데이터량이 적은 경우는 블록의 내용이 효율적으로 이용되어 있지 않은 경우를 생각할 수 있습니다. 예를 들면 데이터 격납 가능 영역이 3000바이트에 대해서 레코드 사이즈가 평균 2000바이트의 경우, 단순 계산이라면 1 블록에 대해 1000바이트의 쓸데없는 공간이 발생하게 됩니다. 테이블이면 DELETE의 기회에 비교해 PCTUSED의 값이 낮은 경우에 블록 레벨의 미사용 영역이 발생하기 쉬워집니다. 인덱스의 경우는 DELETE가 많은 경우, 인덱스 대상열의 값이 승순은 아니고 랜덤이나 내림차순에 INSERT 되는 경우, 인덱스 대상열에 대해서 갱신이 발생하는 것이 많은 경우에 블록 레벨의 미사용 영역이 발생하기 쉬워집니다. 용량 견적 서비스등을 이용하고, 이론적인 견적치에 대해서 실제의 용량(HWM까지의 용량)이 너무 큰 경우는 재편성을 검토한다. 특히 풀 스캔의 경우는 견적치와 실제치의 비에 가까운 레벨로 처리 시간이 걸립니다.


출처 : http://blog.naver.com/hirokorea?Redirect=Log&logNo=20023344842
반응형

'ORACLE > TUNING' 카테고리의 다른 글

AWR (Automatic Workload Repository)  (0) 2010.03.23
Statspack 생성/삭제/Sanpshot생성  (0) 2010.03.23
Oracle Hidden Parameter 란  (0) 2010.01.26
FAST_START_MTTR_TARGET  (0) 2010.01.18
EXPLAIN PLAN(실행계획) 이란  (0) 2010.01.12
Posted by [PineTree]