데이터베이스 연구실.log

UNDO 공간과 보존 (UNDO_RETENTION, RETENTION GUARANTEE)

UNDO 정보의 세 상태(Active, Unexpired, Expired), UNDO_RETENTION이 실제로 동작하는 조건, RETENTION GUARANTEE의 효과와 위험, UNDO 테이블스페이스 생성

ORA-01555snapshot too oldUNDOUNDO_RETENTIONRETENTION GUARANTEEUNEXPIREDUNDO TABLESPACE

#핵심 요약

UNDO 정보는 Active(커밋되지 않음), Unexpired(커밋됐지만 보존 기간 안), Expired(덮어쓰기 가능)로 나뉨

UNDO_RETENTION은 커밋된 UNDO를 최소 몇 초 보존할지 정하는 값임
고정 크기 UNDO 테이블스페이스에서는 무시되고, 자동 확장 테이블스페이스에서만 이 값을 지키려 함

RETENTION GUARANTEE를 켜면 Unexpired UNDO를 덮어쓰지 않음
대신 공간이 모자라면 DML이 실패할 수 있음

#개념과 동작 원리

상태 의미
Active 커밋되지 않은 트랜잭션의 UNDO
Unexpired 커밋됐지만 나이가 현재 보존 기간보다 짧은 UNDO
읽기 일관성과 Flashback을 위해 보존
Expired 보존 기간이 지난 UNDO
새 트랜잭션이 덮어쓸 수 있음

#UNDO_RETENTION이 동작하는 조건

Oracle은 UNDO 테이블스페이스 크기와 시스템 활동을 보고 보존 기간을 자동으로 조정함
UNDO_RETENTION(초)은 선택적으로 주는 최소 보존 기간임

고정 크기 UNDO 테이블스페이스에서는 UNDO_RETENTION이 무시됨

자동 확장(AUTOEXTEND) UNDO 테이블스페이스에서는 이 값을 지키려 하며, 공간이 모자라면 Unexpired를 덮어쓰는 대신 테이블스페이스를 늘림
MAXSIZE에 도달하면 Unexpired를 덮어쓰기 시작할 수 있음

DBCA가 만드는 UNDOTBS1은 자동 확장임

CDB에서 UNDO_RETENTION은 PDB로 상속되지 않음

#RETENTION GUARANTEE

기본값은 꺼짐임
CREATE DATABASE, CREATE UNDO TABLESPACE 때 지정하거나 나중에 ALTER TABLESPACE로 켜고, RETENTION NOGUARANTEE로 끔

켜면 여러 DML이 실패할 수 있으므로 주의해서 씀

설정 상태는 DBA_TABLESPACES.RETENTION 열에서 확인함

#필수 명령어 또는 SQL

#보존 기간과 UNDO 테이블스페이스 확인

SQL*Plus조회만 함
SHOW PARAMETER undo_retention
SHOW PARAMETER undo_tablespace
SELECT tablespace_name, retention FROM dba_tablespaces WHERE contents = 'UNDO';

결과 해석:

#RETENTION GUARANTEE 켜기

SQL*Plus객체 또는 설정을 변경함
ALTER TABLESPACE undotbs1 RETENTION GUARANTEE;

결과 해석: 개별 실행 출력은 기재 없음

#UNDO 테이블스페이스 생성

SQL*Plus객체 또는 설정을 변경함
CREATE UNDO TABLESPACE undotbs2
  DATAFILE '/home/oracle/undotbs2_01.dbf' SIZE 100M
  RETENTION GUARANTEE;

결과 해석:

실습에서는 새 UNDO 테이블스페이스를 만든 뒤 UNDO_TABLESPACE 파라미터를 바꿔야 사용된다고 적었음
바꾸는 명령은 기재 없음

#UNDO의 용도와 ORA-01555 재현

UNDO 데이터의 용도는 세 가지임: 트랜잭션 롤백, 트랜잭션 복구(인스턴스 복구 때 커밋되지 않은 변경 되돌리기), 읽기 일관성

ORA-01555: snapshot too old는 데이터를 바꾸지 않는 SELECT에서도 남
긴 조회는 시작 시점의 데이터를 끝까지 일관되게 보려 하는데, 그 시점 데이터를 다시 만드는 데 필요한 UNDO가 이미 덮어써졌을 때 생김
예를 들어 월말 리포트 SQL이 큰 테이블을 오래 읽는 동안 배치가 같은 데이터를 대량으로 바꾸고 자주 커밋하면 리포트가 중간에 실패함

실습에서는 작은 UNDO에서 일부러 재현했음(운영 DB에서 하면 안 됨)

SQL*Plus (SYSDBA, 실습 DB만)객체 또는 설정을 변경함
SELECT name, value FROM v$parameter WHERE name LIKE 'undo%' ORDER BY name;   -- 원래 UNDO_TABLESPACE 기록

CREATE UNDO TABLESPACE small_undo
  DATAFILE '<DATAFILE_DIR>/small_undo.dbf' SIZE 10M AUTOEXTEND OFF;
ALTER SYSTEM SET undo_tablespace = small_undo;
SQL*Plus (실습 계정)객체 또는 설정을 변경함
CREATE TABLE t1 (c1 INT, c2 CHAR(300));
INSERT /*+ append */ INTO t1 SELECT level, 'dummy' FROM dual CONNECT BY level <= 10000;
COMMIT;
CREATE INDEX t1_n1 ON t1(c1);

CREATE OR REPLACE FUNCTION fsleep(v1 INT, vsleep INT) RETURN NUMBER IS
BEGIN
  DBMS_LOCK.SLEEP(vsleep);
  RETURN 1;
END;
/
세션 A (실습 계정)조회만 함
SELECT /*+ index(t1) */ c1, SUBSTR(c2, 1, 10) AS c2_value
  FROM t1
 WHERE fsleep(c1, 0.01) = 1 AND c1 > 0;     -- 일부러 천천히 읽는 긴 조회
세션 B (실습 계정)객체 또는 설정을 변경함
BEGIN
  FOR idx IN 1 .. 1000 LOOP
    FOR idx2 IN 1 .. 10000 LOOP
      UPDATE t1 SET c2 = 'dummy' || idx WHERE c1 = idx2;
      COMMIT;
    END LOOP;
  END LOOP;
END;
/

결과 해석: 세션 B가 커밋할 때마다 그 UNDO는 롤백용이 아니게 되고, 작은 UNDO 안에서 빠르게 재사용됨
세션 A가 시작 시점 데이터를 다시 만들 UNDO를 찾지 못하면 ORA-01555로 실패함

바로 재현되지 않으면 UNDO를 더 작게, 세션 B를 더 오래, fsleep 값을 더 크게 함
실습 자료는 DB_CACHE_SIZE를 작게 줄이는 방법도 들었지만 실습 DB에서만 씀

예방: UNDO 테이블스페이스를 충분히 크게 두고, UNDO_RETENTION을 회사에서 가장 오래 도는 쿼리 시간에 맞춤
NOGUARANTEE이면 공간이 모자랄 때 보존 시간 안의 UNDO도 재사용될 수 있음

실습이 끝나면 ALTER SYSTEM SET undo_tablespace = <원래 UNDO>로 되돌림

#사용 조건과 주의사항

고정 크기 UNDO 테이블스페이스에서 UNDO_RETENTION만 늘려서는 보존 기간이 보장되지 않음

RETENTION GUARANTEE는 DML 실패 위험이 있음
운영 환경에서는 영향을 확인한 뒤 씀

SEO_HKabsumveritas@gmail.comBuilt with Claude Code & Codex

마지막 갱신 개인 학습 기록이며 운영 환경 적용 전 공식 문서 확인 필요

두 글자 이상 입력, 위아래 화살표로 이동하고 Enter로 열기