반응형

용량이 부족하여 DB 데이터를 삭제해야 하는 상황이였다.

이번에 작업하며 생각한 것들을 글로 정리하고자 한다.

(결과는 없음.. 결국 삭제 배치를 만들긴 했으나 반영하진 않았으니깐..)

 

delete 쿼리를 반복하여 실행하여 삭제하려고 하였었다.

파이썬 코드에서 쿼리를 실행하려 하였고, 삭제대상 날짜를 바인딩하여 쿼리에 넣어 실행하려 하였었다.

=> 이 방법으론 진행하지 않았다.

현상황에서 저 방법은 위험하여 결국 다른 방법으로 하기로 하였다

 

 

 

데이터를 삭제하고자 하는 테이블은 계속해서 인서트, 업뎃이 일어나는 테이블이다.

인덱스가 없고 파티션 테이블도 아니다.

데이터가 nn억개가 있었고 특정 기간의 데이터를 삭제하려 했다.

풀스캔이라 엄청 오래 걸릴것이다.. 결국 운영에선 해보지 않았다.

 

내 리눅스 서버에 오라클DB 설치해서 테스트했을땐 2억개 데이터 있는 테이블에서 10만개 지우는데 15분정도 걸렸다

서버 성능에 따라 다르고 테이블 데이터 개수에 따라 천차만별로 다를 듯

 

운영엔 nn억개 데이터가 있고... 훨씬 많아서 훨씬 오래 걸릴 것으로 예상되었고,

텍스트 데이터라서 많이 지우더라도 용량이 딱히 큰 차이가 없을 것 같았다.

 

 


 

 

 

찾아본 점

 

 

 

인덱스가 있는지

 

확인방법

SELECT * FROM USER_IND_COLUMNS WHERE TABLE_NAME IN ('테이블명1', '테이블명2', '테이블명3');

 

=> 실행시 같은 TABLE_NAME에 COLUMN_POSITION이 1, 2, .. 여러개 나오면 인덱스가 여러개 걸려있는 것임

 

확인해보니 인덱스는 잡혀 있는데, 첫번째 인덱스의 값이 null이라서 사용하지 못했다.

총 3개가 걸려있었는데, 첫번째를 걸지 못하면 2,3번째 칼럼을 조건에 사용하더라도 인덱스를 사용하지 않게 된다고 한다.

 

 

 

사용하려는 쿼리가 인덱스를 사용중인지

EXPLAIN PLAN FOR 사용하여 확인

 

 

 

삭제하려는 테이블의 용량

select bytes/1024/1024/1024 from dba_segments where segment_name='테이블명'

 

했을 때 거의 300G 나왔다.

 

 

 

힌트 사용 가능한지

속도가 너무 느려서 병렬처리를 할 수 있는 힌트( parallel )를 사용하고자 하였다.

parallel 힌트는 조회에서도 줄 수 있고, 삭제에서도 줄 수 있다.

그런데 삭제쿼리에서는 해당 힌트를 사용할 경우 커밋을 하기 전까지

해당 테이블에 select, insert, update, delete를 하려고 하면 오라클 에러를 바로 뱉었다.

 

parallel 힌트를 주는 경우엔 커밋 전에 접근하고자 하면 에러를 뱉는다..ㅠㅠ

그래서 작업 도중에 해당 테이블에 접근할 가능성이 있으면 아예 병렬 힌트는 못쓴다

 

 

 

# 병렬모드 확인

DEGREE에 나오는게 4이면 parallel 4 를 할 수 있음 (cpu 4개 사용한단 뜻)

SELECT TABLE_NAME, DEGREE FROM ALL_TABLES WHERE TABLE_NAME like '%테이블명%';

 

 

# 병렬모드 활성화

ALTER SESSION ENABLE PARALLEL DML;
ALTER TABLE 테이블명 PARALLEL 4;

 

 

# 병렬 해제

ALTER TABLE 테이블스페이스명.테이블명 NOPARALLEL;

=> 이 쿼리 실행 후 위 쿼리 실행하면 DEGREE가 1로 나옴 

 

 

# 쿼리에서 사용할때 예시 

/*+ 를 붙여써야 한다

SELECT /*+ PARALLEL(테이블명, 4) */
FROM 테이블명;

 

 

# EXPLAN FOR 사용

EXPLAIN PLAN FOR
DELETE /*+ PARALLEL(테이블명, 4) */
FROM 테이블명
WHERE COLUMN1 < TO_DATE('2019-12-31', 'YYYY-MM-DD');

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

 

 

 

로우락 vs 테이블락

로우락인 경우 실행중인 열에 대해서만 잠궈버려서 접근이 불가능하다.

삭제하는 쿼리를 실행중일 때

새로운 데이터를 인서트하고, 삭제대상이 아닌 열을 업데이트와 삭제를 할 땐 영향을 안준다.  

 

테이블락인 경우엔 삭제 대상 열이 아니더라도 테이블 자체를 잠궈버려서 락이 풀릴 때까지 기다린다.

 

gpt 한테 열심히 물어본 결과

락이여도 풀릴때까지 기다린다고 함. 누락되진 않고 기다린다고 하더군요.

(저는 에러를 뱉거나 해서 누락되는 줄)

또 로우락이여도 삭제쿼리가 풀스캔이면 기다릴 수 있다 함

 

문제는 실행하려는 쿼리가 엄청 오래 소요될 것으로 예상되었다.

그래서 이게 하다가 락 걸린 상태로 계ㅔ속 있으면 설정에 따라 타임아웃이 나서 누락될 수도 있을 것 같았다.

(오직 내 생각이고 예상일뿐 막상 돌렸을 때 잘 돌아갔을 수도 있긴 하다. 그치만 완전 위험한건 맞음)

 

 

 

 

DELETE 쿼리 실행시 실제로 용량이 줄어드는지

확인해보니 DELETE쿼리 실행한 후 

SHRINK SPACE란걸 실행해서 공간 정리를 해야 용량이 줄어들고

실제로 새로운 데이터의 저장 공간이 생긴다고 함.

 

DELETE쿼리만 실행한다 해서, 삭제된 빈 공간을 테이블스페이스에 반환하지 않는 듯

(이 역시 직접 확인해본 건 아니라 정확하지 않음..ㅎㅎㅋ)

=> 이후에 확인해보니 용량을 반환하진 않지만 빈 공간으로 남아있어서 insert시 해당 공간을 활용하는듯!!!


 

테이블에 데이터 양이 많을 때

풀스캔하는 DELETE 쿼리는 느려서 부하를 줄 수 있으니

그대로 사용하는 것보단 다른 방법이 있는지 찾아보기..

인덱스가 있는지, 힌트 사용이 가능한지, 백업 테이블 만들 수 있는지, 파티션별로 삭제가 가능한지 등등 .. 

 

 

 

반응형
복사했습니다!