PDB 시점 복구와 TSPITR
PDB 시점 복구, 보장 복원 지점, 테이블스페이스 TSPITR과 RECOVER TABLE의 조건 및 복구 범위 비교
#핵심 요약
PDB 시점 복구는 그 PDB만 닫고 루트에서 SET UNTIL SCN과 함께 RESTORE/RECOVER PLUGGABLE DATABASE를 실행한 뒤 OPEN RESETLOGS로 엶
다른 PDB와 CDB는 계속 열어 둘 수 있음
Flashback Pluggable Database는 백업을 복원하지 않고 플래시백 로그로 PDB를 되감으므로 PDB 시점 복구보다 빠름
CDB의 플래시백과 PDB 복원 지점이 필요함
TSPITR은 PDB 안의 테이블스페이스 하나만 과거로 되돌림
보조 인스턴스 위치(AUXILIARY DESTINATION)가 필요하고, 끝나면 테이블스페이스가 OFFLINE으로 남으므로 새로 백업한 뒤 온라인으로 올림
범위가 클수록 함께 과거로 가는 정상 데이터도 많음
테이블 하나만 문제면 RECOVER TABLE ... OF PLUGGABLE DATABASE로 그 테이블만 꺼냄
#개념과 동작 원리
PDB 시점 복구 때 RMAN은 루트에 SYSDBA 또는 SYSBACKUP 공통 사용자로 접속하고, 복구할 PDB만 닫음
나머지 PDB와 CDB는 열려 있어도 됨
CDB가 local undo면 PDB 플래시백은 그 PDB 데이터 파일만 바꾸면 되므로 간단함
shared undo면 보조 인스턴스를 쓰며 기본 위치는 FRA임
PDB 복원 지점은 만든 PDB에서만 쓸 수 있음
보장 PDB 복원 지점은 CDB의 플래시백 로그 재사용을 막아 FRA가 가득 찰 수 있으므로 신중히 만듦
PDB 백업은 PDB 플래시백 뒤에도 유효함
PDB 백업이 자기 완결적인 것은 local undo일 때뿐임(백업 보존과 정리의 KEEP 설명)
| 방법 | 과거로 가는 범위 |
|---|---|
| CDB 전체 시점 복구 | 루트와 모든 PDB |
| PDB 시점 복구 | PDB 하나 전체 |
| TSPITR | PDB의 테이블스페이스 하나(그 안의 모든 테이블) |
RECOVER TABLE |
테이블 하나 |
TSPITR은 잘못된 작업이 같은 테이블스페이스의 여러 테이블에 걸쳐 있을 때 쓰고, 그 시점 이후 같은 테이블스페이스에 들어온 정상 데이터도 함께 사라짐
CDB에서는 PDB마다 같은 이름의 테이블스페이스(USERS 등)가 있을 수 있어 <PDB_NAME>:<TABLESPACE>로 구분함(non-CDB는 테이블스페이스 이름만 씀)
| 방법 | 범위 | 백업 복원 | 조건 |
|---|---|---|---|
| PDB 시점 복구 | PDB 전체 | 함 | 대상 시점 이전 백업 shared undo면 AUXILIARY DESTINATION |
| Flashback PDB | PDB 전체 | 안 함 | CDB 플래시백 켜짐, PDB 복원 지점 |
| TSPITR | PDB 안의 테이블스페이스 | 함(보조 인스턴스) | 테이블스페이스 자기 완결성, AUXILIARY DESTINATION |
#필수 명령어 또는 SQL
#PDB 시점 복구
SELECT property_value FROM database_properties WHERE property_name = 'LOCAL_UNDO_ENABLED';
ARCHIVE LOG LIST결과 해석:
실습 기록: LOCAL_UNDO_ENABLED는 TRUE였음
실습에서는 FALSE면 AUXILIARY DESTINATION을 붙이라고 적었음
BACKUP PLUGGABLE DATABASE <PDB_NAME> PLUS ARCHIVELOG;SELECT current_scn FROM v$database;결과 해석:
실습에서는 되돌릴 기준 SCN을 기록한 뒤 테이블을 DROP ... PURGE로 지웠음
휴지통을 거치지 않으므로 Flashback Drop으로는 되살릴 수 없는 상황임
ALTER PLUGGABLE DATABASE <PDB_NAME> CLOSE IMMEDIATE;RUN {
SET UNTIL SCN <SCN>;
RESTORE PLUGGABLE DATABASE <PDB_NAME>;
RECOVER PLUGGABLE DATABASE <PDB_NAME>;
}ALTER PLUGGABLE DATABASE <PDB_NAME> OPEN RESETLOGS;SELECT con_id, pdb_incarnation#, status, incarnation_time
FROM v$pdb_incarnation WHERE con_id = <CON_ID> ORDER BY pdb_incarnation#;결과 해석:
설명: 리두 로그는 CDB 전체가 함께 쓰므로 PDB를 OPEN RESETLOGS해도 CDB의 로그 시퀀스는 1로 돌아가지 않고 이어짐
새로 생기는 것은 그 PDB만의 incarnation이며 V$DATABASE_INCARNATION이 아니라 V$PDB_INCARNATION에서 확인함
새 PDB incarnation이 CURRENT로 추가됨
CDB 루트는 복구 동안 READ WRITE 상태였음
실습에서는 복구 뒤 로그 시퀀스가 "처음 기록과 같거나 이어지는 번호"라고 적었지만, 처음 기록은 34이고 복구 뒤 기록은 15였음
#RAC에서 PDB 시점 복구
ALTER PLUGGABLE DATABASE <PDB_NAME> CLOSE IMMEDIATE INSTANCES = ALL;
SELECT inst_id, name, open_mode FROM gv$pdbs WHERE name = '<PDB_NAME>';RUN {
SET UNTIL TIME "TO_DATE('<YYYY-MM-DD HH24:MI:SS>', 'YYYY-MM-DD HH24:MI:SS')";
-- 또는 SET UNTIL RESTORE POINT <RESTORE_POINT>;
RESTORE PLUGGABLE DATABASE <PDB_NAME>;
RECOVER PLUGGABLE DATABASE <PDB_NAME>;
}
ALTER PLUGGABLE DATABASE <PDB_NAME> OPEN RESETLOGS;ALTER PLUGGABLE DATABASE <PDB_NAME> OPEN INSTANCES = ('<OTHER_INSTANCE>');결과 해석:
복원, 리두 적용 동안 다른 인스턴스가 같은 PDB 파일을 쓰지 않도록 INSTANCES = ALL로 모든 노드에서 닫음
CDB 루트와 다른 PDB는 계속 열어 둠
OPEN RESETLOGS는 복구한 인스턴스에서 한 번만 하고, 나머지 인스턴스는 일반 OPEN으로 엶
실습 기록: 2번 노드에서 DROP TABLE t_pitr PURGE 뒤 ALTER SYSTEM ARCHIVE LOG CURRENT로 모든 thread를 아카이브하고, 1번 노드에서 기록해 둔 시각으로 복구하자 2번 노드에서 500건이 다시 보였음
로컬 UNDO 모드라 RMAN 출력에 보조 인스턴스 생성 과정이 없었고, CDB incarnation은 그대로 두고 그 PDB의 incarnation만 새로 CURRENT가 됐음
데이터 파일, 컨트롤 파일, 아카이브가 공유 저장소(+DATA, +FRA)에 있어 실수한 노드와 다른 노드에서도 복구할 수 있음
연습 문제: 2번 노드의 월말 배치가 t_order를 TRUNCATE했고 배치 직전에 루트에서 CREATE RESTORE POINT before_close_batch를 만들어 둔 상황에서, 정확한 시각 없이 SET UNTIL RESTORE POINT로 2번 노드에서만 복구하고 두 인스턴스에서 1,000건을 확인함
#Flashback Pluggable Database
SELECT flashback_on FROM v$database;
ALTER DATABASE FLASHBACK ON;결과 해석:
설명: ARCHIVELOG 모드이고 FRA가 설정되어 있으면 열린 상태에서 바로 켤 수 있음
플래시백 로그는 FRA의 flashback 디렉터리에 쌓임
ALTER SESSION SET CONTAINER = <PDB_NAME>;
CREATE RESTORE POINT before_del GUARANTEE FLASHBACK DATABASE;
SELECT name, con_id, guarantee_flashback_database, scn FROM v$restore_point;결과 해석:
설명: PDB 안에서 만든 복원 지점은 그 PDB 전용임
ALTER PLUGGABLE DATABASE <PDB_NAME> CLOSE IMMEDIATE;
FLASHBACK PLUGGABLE DATABASE <PDB_NAME> TO RESTORE POINT before_del;
ALTER PLUGGABLE DATABASE <PDB_NAME> OPEN RESETLOGS;ALTER SESSION SET CONTAINER = <PDB_NAME>;
DROP RESTORE POINT before_del;
ALTER SESSION SET CONTAINER = CDB$ROOT;
ALTER DATABASE FLASHBACK OFF;결과 해석:
설명: 보장 복원 지점을 지우지 않으면 플래시백 로그가 FRA에 계속 쌓여 가득 찰 수 있음
공식 문서도 같은 위험을 적음
#PDB 안의 테이블스페이스만 되돌리기 (TSPITR)
실습에서는 테이블과 인덱스를 같은 테이블스페이스로 옮기고(ALTER TABLE ... MOVE, ALTER INDEX ... REBUILD), 두 번째 테이블을 만든 뒤 백업하고 SCN을 기록했음
그 다음 한 테이블에는 정상 행을 넣고 다른 테이블의 행을 실수로 지웠음
EXEC DBMS_TTS.TRANSPORT_SET_CHECK('<TABLESPACE_NAME>', TRUE);
SELECT * FROM transport_set_violations;
SELECT owner, name, creation_time
FROM ts_pitr_objects_to_be_dropped
WHERE tablespace_name = '<TABLESPACE_NAME>'
AND creation_time > SCN_TO_TIMESTAMP(<SCN>);결과 해석:
설명: TRANSPORT_SET_VIOLATIONS에 행이 나오면 다른 테이블스페이스 객체와 얽혀 있어 TSPITR을 할 수 없음(예: 인덱스만 다른 테이블스페이스에 있음)TS_PITR_OBJECTS_TO_BE_DROPPED에 나오는 객체는 그 시점 이후에 만들어져 TSPITR 뒤 사라지므로 필요하면 미리 Data Pump로 빼 둠
실습 기록: violations는 "no rows selected"였음
RECOVER TABLESPACE <PDB_NAME>:<TABLESPACE_NAME>
UNTIL SCN <SCN>
AUXILIARY DESTINATION '<AUX_DIR>';
BACKUP TABLESPACE <PDB_NAME>:<TABLESPACE_NAME>;SELECT tablespace_name, status FROM dba_tablespaces WHERE tablespace_name = '<TABLESPACE_NAME>';
ALTER TABLESPACE <TABLESPACE_NAME> ONLINE;결과 해석:
설명: TSPITR 동안 루트와 그 PDB의 다른 테이블스페이스는 계속 서비스됨
끝나면 테이블스페이스가 OFFLINE으로 남고 이전 백업은 더 쓸 수 없으므로 온라인으로 올리기 전에 새로 백업함
실습 기록: 실수로 지운 행은 돌아왔고, 같은 테이블스페이스의 다른 테이블에 기준 SCN 뒤에 넣은 정상 행은 함께 사라졌음
TSPITR 관련 공식 문서 문장은 확인 불가
#PDB 안의 테이블 하나만 복구 (RECOVER TABLE)
DROP TABLE ... PURGE로 지워 휴지통에서도 되살릴 수 없거나, 데이터만 잘못 지운 테이블 하나를 과거 시점으로 꺼낼 때 씀
RMAN이 보조 인스턴스를 만들어 그 시점까지 복원, 복구한 뒤 Data Pump로 테이블을 내보내고 가져옴
동작 순서: AUXILIARY DESTINATION에 보조 인스턴스 생성, 루트와 PDB의 SYSTEM, SYSAUX, UNDO와 테이블이 있는 테이블스페이스를 복원, UNTIL 시점까지 복구, Data Pump로 내보내 운영 PDB에 가져오기, 보조 인스턴스와 파일 자동 삭제
non-CDB에서는 OF PLUGGABLE DATABASE 없이 RECOVER TABLE <OWNER>.<TABLE_NAME> UNTIL SCN ... AUXILIARY DESTINATION ...으로 씀
쓸 수 없는 경우: ARCHIVELOG 모드가 아니거나 되돌릴 시점 이전 백업이 없을 때, SYS, SYSTEM 소유 테이블이나 SYSTEM, SYSAUX 테이블스페이스의 테이블, 보조 인스턴스 위치에 공간(수 GB)이 없을 때
보조 인스턴스에는 루트와 그 PDB의 SYSTEM, SYSAUX, UNDO가 복원되므로 PDB만 백업해서는 부족하고 CDB 전체 백업이 필요함
실습 자료는 보조 인스턴스 위치에 최소 5GB 이상 여유 공간(TEMP 테이블스페이스 공간 포함)을 두고, 보조 인스턴스도 메모리를 쓰므로 다른 DB는 내려 두라고 적었음
mkdir -p <AUX_DIR>
df -h <AUX_DIR>SELECT owner, table_name, tablespace_name FROM dba_tables WHERE owner = '<OWNER>';
SELECT current_scn FROM v$database; -- 사고 전 SCN을 적어 둠
SELECT SCN_TO_TIMESTAMP(<SCN>) FROM dual; -- SCN을 시각으로
SELECT TIMESTAMP_TO_SCN(TO_TIMESTAMP('<YYYY-MM-DD HH24:MI:SS>', 'YYYY-MM-DD HH24:MI:SS')) FROM dual; -- 시각을 SCN으로BACKUP DATABASE PLUS ARCHIVELOG;
RECOVER TABLE <OWNER>.<TABLE_NAME> OF PLUGGABLE DATABASE <PDB_NAME>
UNTIL SCN <SCN>
AUXILIARY DESTINATION '<AUX_DIR>';결과 해석:
OF PLUGGABLE DATABASE를 빼면 루트에서 테이블을 찾다가 실패함
진행 순서: 보조 인스턴스 생성, restore, recover, Performing export of tables, Performing import of tables, Removing automatic instance 순서로 출력됨
복구 동안 그 PDB는 계속 열려 있고 다른 테이블은 영향이 없음
결과 확인: 사고 전에 적어 둔 건수와 같은지 보고, <AUX_DIR>의 보조 인스턴스 파일이 정리됐는지 확인함
테이블이 아직 남아 있고 데이터만 지워졌다면 같은 이름으로 복구하면 충돌하므로 다른 이름으로 꺼내 필요한 행만 되넣음
RECOVER TABLE <OWNER>.<TABLE_NAME> OF PLUGGABLE DATABASE <PDB_NAME>
UNTIL SCN <SCN>
AUXILIARY DESTINATION '<AUX_DIR>'
REMAP TABLE '<OWNER>'.'<TABLE_NAME>':'<TABLE_NAME>_OLD';INSERT INTO <TABLE_NAME>
SELECT * FROM <TABLE_NAME>_OLD
WHERE <KEY_COLUMN> NOT IN (SELECT <KEY_COLUMN> FROM <TABLE_NAME>);
COMMIT;
DROP TABLE <TABLE_NAME>_OLD PURGE;결과 해석:
REMAP TABLE의 이름은 대문자와 작은따옴표로 적음
운영 PDB에 바로 넣지 않고 덤프 파일만 받으려면 NOTABLEIMPORT와 DATAPUMP DESTINATION '<AUX_DIR>' DUMP FILE '<FILE>.dmp'를 붙임
#사용 조건과 주의사항
세 방법 모두 대상 시점 이후의 변경을 그 범위 안에서 잃음
범위를 먼저 고름
실습에서는 샘플 계정 접속 문자열에 비밀번호를 적었음