프린트 하기

OS 환경 : Oracle Linux 8.1 (64bit)

 

DB 환경 : Oracle Database 19.3.0.0

 

방법 : 오라클 19c 데이터 1천만건 delete 시간 측정

오라클에서 컬럼이 12개인 테이블에 데이터를 1200만건 넣은 후 1000만건을 delete로 지우는 테스트를 진행해봄
이때 인덱스도 2개 생성하여 지울때 시간이 얼마나 걸리는지 확인해봄

 

 

테스트
테이블 생성

1
2
3
4
5
6
7
8
9
SQL>
drop table sample_t purge;
create table sample_t 
(id1 number, id2 number, name varchar2(10),  
date1 varchar2(8), date2 varchar2(8), date3 date, 
phone varchar2(13), price number, qty number, 
test1 number,  test2 varchar2(5), test3 varchar2(4)
)
nologging;

 

 

인덱스 생성

1
2
3
SQL>
create index sample_t_ix01 on sample_t(id1, id2, name);
create index sample_t_ix02 on sample_t(test1, price, qty);

 

 

데이터 삽입(10만건)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
SQL>
DECLARE
TYPE tbl_ins IS TABLE OF sample_t%ROWTYPE INDEX BY BINARY_INTEGER;
w_ins tbl_ins;
BEGIN
FOR i IN 1..100000 LOOP 
   w_ins(i).id1   := i;
   w_ins(i).id2   := i||ceil(dbms_random.value(1, 10000000));
   w_ins(i).name  := dbms_random.string('x',5);
   w_ins(i).date1 := round(dbms_random.value(2010,2021))||to_char(round(dbms_random.value(1,12)), 'FM09')||to_char( round(dbms_random.value(1,28)), 'FM09');
   w_ins(i).date2 := '2021'||to_char(round(dbms_random.value(1,12)) , 'FM09')||to_char(round(dbms_random.value(1,28)), 'FM09');
   w_ins(i).date3 := to_date(round(dbms_random.value(2010,2021))||'-'||round(dbms_random.value(1,12))||'-'||round(dbms_random.value(1,28))||' '||round(dbms_random.value(1, 23))||':'||round(dbms_random.value(0, 59))||':'||round(dbms_random.value(0, 59)), 'YYYY-MM-DD HH24:MI:SS');
   w_ins(i).phone := '010-'||ceil(dbms_random.value(1000, 9999))||'-'||ceil(dbms_random.value(1000, 9999));
   w_ins(i).price := ceil(dbms_random.value(1, 10))*1000;
   w_ins(i).qty   := ceil(dbms_random.value(1, 10));
   w_ins(i).test1 := 1234;
   w_ins(i).test2 := 'SQLP';
   w_ins(i).test3 := 'A'||ceil(dbms_random.value(100, 999));
END LOOP;
FORALL i in 1..100000 INSERT INTO sample_t VALUES w_ins(i);
   COMMIT;
END;
/
 
PL/SQL procedure successfully completed.

 

 

크기 확인

1
2
3
4
5
6
7
8
9
10
11
12
SQL> 
set lines 200 pages 1000
col segment_name for a15
select segment_name, bytes/1024/1024 mb 
from dba_segments 
where segment_name like 'SAMPLE_T%';
 
SEGMENT_NAME            MB
--------------- ----------
SAMPLE_T                10
SAMPLE_T_IX01            3
SAMPLE_T_IX02            4

테이블은 10mb, 인덱스1은 3, 인덱스2는 4mb임

 

 

itas 반복해서 데이터 늘리기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SQL>
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;
insert /*+ parallel(s) append */ into sample_t s select /*+ parallel(s) */ * from sample_t s;
commit;

 

 

크기 확인

1
2
3
4
5
6
7
8
9
10
11
12
SQL> 
set lines 200 pages 1000
col segment_name for a15
select segment_name, bytes/1024/1024 mb 
from dba_segments 
where segment_name like 'SAMPLE_T%';
 
SEGMENT_NAME            MB
--------------- ----------
SAMPLE_T              1216
SAMPLE_T_IX01          424
SAMPLE_T_IX02          296

테이블은 1216mb임

 

 

테이블 logging으로 변경

1
2
3
SQL> alter table sample_t logging;
 
Table altered.

 

 

테이블 카운트 확인

1
2
3
4
5
SQL> select count(*) from sample_t;
 
  COUNT(*)
----------
  12800000

 

 

로그 스위치 횟수 측정을 위해 수동 로그스위치 5회 및 체크포인트 5회 수행

1
2
3
4
SQL> @lscp
 
System altered.
..

 

 

delete로 1천만건 데이터 삭제(언두가 삭제할 데이터보다 커야함)

1
2
3
4
5
6
7
SQL> 
set timing on
delete sample_t where rownum <= 10000000;
 
10000000 rows deleted.
 
Elapsed: 00:09:01.97

9분 1초 소요됨

 

 

커밋

1
2
3
SQL> commit;
 
Commit complete.

*참고로 현재 redo는 1gb로 설정되어 있고 작업시 로그스위치는 8회 발생함

 

 

용량 확인

1
2
3
4
5
SQL> select segment_name, bytes/1024/1024 mb from dba_segments where segment_name = 'SAMPLE_T';
 
SEGMENT_NA         MB
---------- ----------
SAMPLE_T         1218

 

 

move online 진행

1
2
3
4
5
SQL> alter table sample_t move online;
 
Table altered.
 
Elapsed: 00:00:15.15

15초 소요됨

 

 

크기 확인

1
2
3
4
5
6
7
8
9
10
11
12
SQL> 
set lines 200 pages 1000
col segment_name for a15
select segment_name, bytes/1024/1024 mb 
from dba_segments 
where segment_name like 'SAMPLE_T%';
 
SEGMENT_NAME            MB
--------------- ----------
SAMPLE_T               256
SAMPLE_T_IX01           96
SAMPLE_T_IX02           72

reorg됨

 

 

인덱스 정보 확인

1
2
3
4
5
6
7
8
9
10
SQL> 
set lines 200 pages 1000
col index_name for a15
col degree for a10
select index_name, status, degree, logging from dba_indexes where index_name like 'SAMPLE_T_IX%';
 
INDEX_NAME      STATUS   DEGREE     LOG
--------------- -------- ---------- ---
SAMPLE_T_IX01   VALID    1          YES
SAMPLE_T_IX02   VALID    1          YES

모두 valid 정상 상태임

 

 

참고로 인덱스를 생성하지 않고 동일 테스트를 진행했을때는 1분 34초 소요되었고
인덱스를 하나만 생성하고 동일 테스트를 진행했을때는 4분 32초 소요되었음
delete 시 index 블록을 처리하는 시간이 빠져서 그런듯함

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#no index
SQL>
set timing on
delete sample_t where rownum <= 10000000;
 
10000000 rows deleted.
 
Elapsed: 00:01:34.78
 
#one index
SQL>
set timing on
delete sample_t where rownum <= 10000000;
 
10000000 rows deleted.
 
Elapsed: 00:04:32.76

 

 

결론 :
동일한 1천만건으로 테스트를 했지만 인덱스 갯수에 따라 delete 시간이 차이가 났음
이렇게 인덱스가 많아으면 많을수록 delete 시간은 급격하게 늘어남
만약 delete 할 데이터가 더 많은 경우 이렇게 delete를 사용하기보다
테이블 껍데기만 새로 생성해서 남길 테이터만 해당 테이블에 넣고 기존 테이블을 truncate 해준뒤 다시 넣거나
기존 테이블 삭제 및 새로 생성한 테이블을 rename, 인덱스 재생성 해주는 방식으로 하는게 더 빠르게 작업할 수 있는 방법임
참고 : 대량 데이터 delete 작업 시 tip(database.sarang.net) ( https://positivemh.tistory.com/204 )

 

 

참조 : 

https://positivemh.tistory.com/204
https://positivemh.tistory.com/808