Oracle 테이블스페이스 용량 급증의 원인

발단

2주라는 짧은 기간동안 특정 테이블스페이스의 사용률이 65%에서 90%로 급증했다.


환경


원인

이미지 파일이나 음성 등의 비정형 데이터를 담는 LOBSEGMENT 사이즈의 증가가 원인이었다.

테이블스페이스의 용량 산정에 오류가 발생한 것이 아니라, 정말로 용량이 늘어난 것이다.


LOB 데이터

LOB이란 Large Object의 약자로, 대용량 데이터를 저장하고 관리하기 위해 오라클에서 제공하는 기본 데이터 타입이다.

LOB 데이터는 사진, 음성, 이미지 등 비구조화된 큰 용량의 파일을 저장하기 때문에 일반 SELECT ... FROM ... SQL문으로는 조회가 불가능하다.


LOB의 종류 (Types of LOBs)


확인방법

특정 테이블스페이스의 용량 분석 과정은 아래와 같다.

1. 테이블별 용량 확인

입력 명령어

-- SQL 실행결과를 가독성 있게 잘 정렬해서 출력하는 부분
SET LINESIZE 300;

-- 실제 수행 SQL문
SELECT TOTAL.TABLESPACE_NAME, ROUND(TOTAL.MB, 2) AS TOTAL_MB, ROUND(TOTAL.MB - FREE.MB, 2) AS USED_MB, ROUND((1 - FREE.MB / TOTAL.MB) * 100, 2) || '%' AS USED_PER
FROM (SELECT TABLESPACE_NAME, SUM(BYTES)/1024/1024 AS MB FROM DBA_FREE_SPACE GROUP BY TABLESPACE_NAME) FREE, (SELECT TABLESPACE_NAME, SUM(BYTES)/1024/1024 AS MB FROM DBA_DATA_FILES GROUP BY TABLESPACE_NAME) TOTAL
WHERE FREE.TABLESPACE_NAME = TOTAL.TABLESPACE_NAME ORDER BY USED_PER DESC;

명령어 결과

TABLESPACE_NAME                  TOTAL_MB    USED_MB USED_PER

------------------------------ ---------- ---------- -----------------------------------------

SYSTEM                               1320    1310.06 99.25%
UNDOTBS1                             1320    1227.88 93.02%
SYSAUX                                900     731.69 81.3%
USERS                                   5          4 80%
SECRET                              30720   24201.69 78.78%
SECRET_IDX                          10240       6.56 .06%

6 행이 선택되었습니다.

문의 오기 전에 이미 개발자 요청에 의해서 SECRET 테이블스페이스에 5GB를 추가해서 사이즈를 30GB로 늘린 상황이다.


2. 개발자의 문의

테이블스페이스의 사용률을 낮춰서 안전하게 조치는 끝났다.

하지만 이후 개발자는 근본적인 테이블스페이스 용량 급증의 원인을 물어봤다.


Developer : “왜 SECRET 테이블스페이스의 용량이 급증한걸까요?”
Sysadmin (me) : (그건 저도 의문입니다.)

이제 본격적으로 테이블스페이스에 연결된 테이블별 용량을 확인하는 단계로 들어간다.


3. 테이블스페이스 용량 확인 (SQL)

입력 명령어

-- SQL 실행결과를 가독성 있게 잘 정렬해서 출력하는 부분
SET LINESIZE 300;
SET PAGES 1000;
COL FILE_NAME FOR A50;

-- 실제 수행 SQL문
SELECT TABLESPACE_NAME, FILE_NAME, ROUND(BYTES/1024/1024/1024, 2) AS GB, ROUND(MAXBYTES/1024/1024/1024, 2) AS MAXGB, AUTOEXTENSIBLE
FROM DBA_DATA_FILES;

명령어 결과

TABLESPACE_NAME                FILE_NAME                                                  GB      MAXGB AUT

------------------------------ -------------------------------------------------- ---------- ---------- ---

SYSTEM                         /data/SECRETDB/system01.dbf                              1.29         32 YES
SYSAUX                         /data/SECRETDB/sysaux01.dbf                               .88         32 YES
UNDOTBS1                       /data/SECRETDB/undotbs01.dbf                             1.29         32 YES
USERS                          /data/SECRETDB/users01.dbf                                  0         32 YES
SECRET                         /data/SECRET                                               30         31 YES
SECRET_IDX                     /data/SECRET_IDX                                           10         20 YES

6 행이 선택되었습니다.

SECRET 테이블스페이스의 데이터 파일은 /data/SECRET에 위치해있고, 현재 할당된 용량은 30GB이다.


4. 테이블스페이스 용량 확인 (OS)

$ ls -lh /data/SECRET
-rw-r----- 1 oracle dba 31G 12월 29 09:22 /data/SECRET

ls -lh 명령어로 확인해본 결과도 sqlplus에서 확인한 결과처럼 동일하게 31GB이다.


5. 테이블스페이스에 속한 테이블 조회

입력 명령어

-- SQL 실행결과를 가독성 있게 잘 정렬해서 출력하는 부분
COL OWNER FOR A10;
COL TABLE_NAME FOR A20;

-- 실제 수행 SQL문
SELECT OWNER, TABLE_NAME, TABLESPACE_NAME
FROM DBA_TABLES
WHERE TABLESPACE_NAME='SECRET';

명령어 결과

OWNER      TABLE_NAME           TABLESPACE_NAME

---------- -------------------- ------------------------------

DEVXXX     XXXXX_XXX            SECRET
DEVXXX     XXXX_XXXXX_TBL       SECRET
DEVXXX     XXXXXXX_TBL          SECRET
DEVXXX     XXXXXXX_XXXX_TBL     SECRET
DEVXXX     XXXX_XXXXX_TBL       SECRET
DEVXXX     XXXX_XXX_TBL         SECRET
DEVXXX     XXXXXX_XXXXX_TBL     SECRET

7 행이 선택되었습니다.

SECRET 테이블스페이스에는 7개의 테이블이 속한다.


6. 테이블별 용량 조회

입력 명령어

-- SQL 실행결과를 가독성 있게 잘 정렬해서 출력하는 부분
SET PAGESIZE 1000;
SET LINESIZE 1000;
COL OWNER FOR A10;
COL SEGMENT_TYPE FOR A15;
COL SEGMENT_NAME FOR A30;
COL TABLESPACE_NAME FOR A15;

-- 실제 수행 SQL문
SELECT OWNER, SEGMENT_TYPE, SEGMENT_NAME, TABLESPACE_NAME, BYTES/1024/1024 MB
FROM DBA_SEGMENTS
WHERE TABLESPACE_NAME='SECRET' ORDER BY MB DESC;

SQL문 상세 설명


명령어 결과

OWNER      SEGMENT_TYPE    SEGMENT_NAME                   TABLESPACE_NAME         MB

---------- --------------- ------------------------------ --------------- ----------

DEVXXX     LOBSEGMENT      SYS_LOB0000233727C00003$$      SECRET           24190.125
DEVXXX     TABLE           XXXX_XXX_XXX                   SECRET                   5
DEVXXX     TABLE           XXXXXXX_XXX                    SECRET                   3
DEVXXX     INDEX           XXXX_XXX_XXX_PK                SECRET                   1
DEVXXX     TABLE           XXXXX_XXX                      SECRET                   1
DEVXXX     LOBSEGMENT      SYS_LOB0000083246C00003$$      SECRET                .125
DEVXXX     TABLE           XXXXXXX_XXXX_XXX               SECRET                .125
DEVXXX     LOBINDEX        SYS_IL0000233727C00003$$       SECRET               .0625
DEVXXX     TABLE           XXXX_XXXXX_XXX                 SECRET               .0625
DEVXXX     TABLE           XXXX_XXXXX_XXX                 SECRET               .0625
DEVXXX     LOBINDEX        SYS_IL0000083246C00003$$       SECRET               .0625
DEVXXX     TABLE           XXXXXXX_XXXX_XXX               SECRET               .0625

12 행이 선택되었습니다.

확인결과
LOBSEGMENT 타입인 SYS_LOB0000233727C00003$$의 용량이 24190MB(=23.6GB)로 늘어난 상태인걸 확인할 수 있다.
일반적인 테이블(TABLE TYPE)들은 정형 데이터를 보관하고 있기 때문에 5MB 이하의 용량이다.
그러나 LOBSEGMENT는 다른 테이블들과 용량 비교를 했을 때 독보적으로 큰 용량임을 알 수 있다.