DB를 사용하다보면 DML 작업이 한 테이블에 많이 일어나게 되고 그렇게 되면 HWM(High Water Mark)는 이전에 데이터가 많았던 지점까지 표시하고 있지만 실제로 사용하는 블록은 그렇지 않게 됩니다. 테이블 크기도 불필요하게 커질 뿐아니라, SCAN시 불필요한 I/O도 발생하게 됩니다. 왜냐하면 Full Scan시 데이터 스캔의 범위기준이 HWM까지이기 때문입니다. 따라서 테이블에 사용하지 않는 공간이 많으면 용량뿐 아니라, 조회 성능도 떨어지는 상황이 발생하게 됩니다.
그것을 해결해주는 방법으로 Shrink와 Table Move 작업이 있습니다.
Shrink는 10g에서 지원하는 기능으로 Online으로 테이블의 HWM을 낮추어 공간을 축소시킬 수 있는 작업입니다. 테스트를 통해 Shrink기능을 테스트해보겠습니다.
OS :OEL 7.6
DB : 12.2.0.1
Shrink
1.테이블과 인덱스 생성
TEST@ysbae> CREATE TABLE HWMTEST(A VARCHAR2(20), B NUMBER, C NUMBER,
D VARCHAR2(30), E VARCHAR2(30));
Table created.
TEST@ysbae> CREATE INDEX IDX_HWM_B ON HWMTEST(B);
Index created.
2.데이터 삽입 (2번 수행하여 총 6000000건의 데이터 삽입)
DECLARE
TYPE tbl_ins IS TABLE OF HWMTEST%ROWTYPE INDEX BY BINARY_INTEGER;
w_ins tbl_ins;
BEGIN
FOR i IN 1..1000000 LOOP
w_ins(i).A :=dbms_random.string('x',10);
w_ins(i).B :=i;
w_ins(i).C :=99;
w_ins(i).D :='ABC'||dbms_random.string('x',10);
w_ins(i).E :='EEEEEEEEEEEEEEEE';
END LOOP;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
END;
/
3.통계정보 수집
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
PL/SQL procedure successfully completed.
4. 실제 사용 블록 및 크기 확인
테이블 360MB에 인덱스 128MB사용중인것을 확인할 수 있으며, dba_segments에서 보이는 블록수와 dbms_rowid로 조회한 실제 사용 블록수의 차이는 적게나타난것을 확인할 수 있습니다.
TEST@ysbae> select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B');
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 46080 360
IDX_HWM_B 16384 128
TEST@ysbae> COL TABLE_NAME FOR A16
SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 6000000 45797
실제사용블록
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
45448
5.데이터 삭제
TEST@ysbae> delete hwmtest where rownum <= 4000000;
4000000 rows deleted.
6.삭제 후 통계정보 재 수집
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
PL/SQL procedure successfully completed.
7.블록 수 및 용량 확인
실제 사용블록은 45448 -> 15151로 줄었지만 용량과 HWM가 찍힌 블록수는 차이가 없는 것을 확인할 수 있습니다.
TEST@ysbae> SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 2000000 45797
select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B')
TEST@ysbae> /
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 46080 360
IDX_HWM_B 16384 128
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
15151
8.Shrink 수행
아래의 권한이 먼저 부여되어야 사용할 수 있습니다. 아니면 밑의 에러를 발생시킵니다.
ORA-10636: ROW MOVEMENT is not enabled
TEST@ysbae> alter table hwmtest enable row movement;
Table altered.
TEST@ysbae> alter table hwmtest shrink space cascade;
Table altered.
+row movement 다시 disable 하기
TEST@ysbae> alter table hwmtest disable row movement;
9. 용량 및 블록 수 다시 확인
용량과 HWM 블록수 모두 줄어든 것을 확인할 수 있습니다.
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
PL/SQL procedure successfully completed.
TEST@ysbae> select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B') ;
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 15320 119.6875
IDX_HWM_B 4600 35.9375
2 rows selected.
TEST@ysbae> SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 2000000 15151
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
15151
Table Move
1.테이블 및 인덱스 생성
TEST@ysbae> CREATE TABLE HWMTEST(A VARCHAR2(20), B NUMBER, C NUMBER,
D VARCHAR2(30), E VARCHAR2(30)) ;
Table created.
TEST@ysbae> CREATE INDEX IDX_HWM_B ON HWMTEST(B);
Index created.
2.데이터 삽입 (5000000건)
TEST@ysbae> DECLARE
TYPE tbl_ins IS TABLE OF HWMTEST%ROWTYPE INDEX BY BINARY_INTEGER;
w_ins tbl_ins;
BEGIN
FOR i IN 1..1000000 LOOP
w_ins(i).A :=dbms_random.string('x',10);
w_ins(i).B :=i;
w_ins(i).C :=99;
w_ins(i).D :='ABC'||dbms_random.string('x',10);
w_ins(i).E :='EEEEEEEEEEEEEEEE';
END LOOP;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
FORALL i in 1..1000000 INSERT INTO HWMTEST VALUES w_ins(i);
COMMIT;
END;
/
PL/SQL procedure successfully completed.
3.통계정보 생성
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
4.용량 및 블록 확인
TEST@ysbae> select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B');
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 38912 304
IDX_HWM_B 16384 128
TEST@ysbae> COL TABLE_NAME FOR A16
SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 5000000 38657
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
37874
1 row selected.
5.데이터 삭제
TEST@ysbae> delete hwmtest where rownum <= 4000000;
4000000 rows deleted.
6.통계정보 재생성 및 확인
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
PL/SQL procedure successfully completed.
TEST@ysbae> SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 1000000 38657
1 row selected.
TEST@ysbae> select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B') ;
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 38912 304
IDX_HWM_B 16384 128
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
7577
1 row selected.
7.Table Move작업 수행
Table Move작업을 수행하면 Rowid가 변경되어서 기존의 Index가 Unusable상태로 변합니다. 반드시 rebuild해주어야 합니다.
TEST@ysbae> alter table hwmtest move tablespace test;
Table altered.
TEST@ysbae> select index_name,status from user_indexes;
INDEX_NAME STATUS
------------------------------
IDX_HWM_B UNUSABLE
TEST@ysbae> alter index IDX_HWM_B rebuild tablespace test;
Index altered.
TEST@ysbae> select index_name,status from user_indexes;
INDEX_NAME STATUS
------------------------------
IDX_HWM_B VALID
8.통계정보재수집 및 확인
TEST@ysbae> exec dbms_stats.gather_table_stats('TEST','HWMTEST');
PL/SQL procedure successfully completed.
TEST@ysbae> SELECT TABLE_NAME,
NUM_ROWS,
BLOCKS
FROM DBA_TABLES
WHERE TABLE_NAME = 'HWMTEST';
TABLE_NAME NUM_ROWS BLOCKS
---------------- ---------- ----------
HWMTEST 1000000 7764
1 row selected.
TEST@ysbae> select segment_name,blocks, bytes/1024/1024 MB from dba_segments
where segment_name in ('HWMTEST','IDX_HWM_B') ;
SEGMENT_NAME BLOCKS MB
---------------- ---------- ----------
HWMTEST 7808 61
IDX_HWM_B 2304 18
TEST@ysbae> SELECT COUNT(DISTINCT
DBMS_ROWID.ROWID_BLOCK_NUMBER(ROWID)||
DBMS_ROWID.ROWID_RELATIVE_FNO(ROWID)) "USED"
FROM HWMTEST;
USED
----------
7634
1 row selected.
마찬가지로 블록수와 용량이 줄어든 것을 확인할 수 있습니다.
테스트의 출처는 아래의 블로그를 참고하여 테스트를 진행하였습니다.
출처 : https://positivemh.tistory.com/350
'Oracle > 운영' 카테고리의 다른 글
Checkpoint와 Checkpoint not complete (0) | 2020.09.09 |
---|---|
Temp Tablespace (0) | 2020.09.08 |
Pivot 함수와 Pivot XML (1) | 2020.08.29 |
특정 테이블의 컬럼의 Update만 인식하는 Trigger 생성하기 (0) | 2020.08.27 |
NUMBER 데이터타입과 데이터타입 변경 (3) | 2020.08.26 |
댓글