운영 중 삭제된 이벤트 페이지, Oracle Flashback Query로 복구한 이야기
Oracle Flashback Query를 활용해 운영 중 삭제된 이벤트 페이지를 복구한 경험을 정리합니다. AS OF TIMESTAMP, UNDO, DELETE/UPDATE 복구 패턴과 실무 주의사항을 다룹니다.
운영 중 실수로 지워진 이벤트 페이지, Oracle Flashback Query로 복구하기
운영 DB를 다루다 보면 가장 무서운 순간은 DELETE, UPDATE 쿼리를 실행한 직후에 찾아옵니다.
실제로 운영 중 이벤트 페이지가 실수로 삭제된 적이 있었습니다. 단순히 내부 테스트용 페이지가 아니라, 이미 여러 광고사에 랜딩 URL이 배포된 이벤트 페이지였습니다. 사용자가 광고를 클릭하면 해당 페이지로 유입되는 구조였고, 페이지 안에는 이벤트 설명, 참여 조건, 안내 문구 등 복구해야 할 내용도 많았습니다.
이런 상황에서는 영향도가 큽니다. 페이지가 사라지면 광고 유입은 계속 발생하지만 사용자는 정상적인 이벤트 페이지를 볼 수 없고, 운영팀 입장에서는 즉시 원복이 필요합니다. 그렇다고 무작정 다시 데이터를 입력하기에는 누락 가능성이 있고, 백업 복구까지 진행하기에는 범위가 너무 큽니다.
이때 사용할 수 있는 기능이 Oracle Flashback Query입니다.
Flashback Query는 AS OF TIMESTAMP, AS OF SCN 문법을 사용해 특정 시점의 테이블 데이터를 조회하는 기능입니다. 핵심은 현재 테이블을 직접 되돌리는 것이 아니라, UNDO 영역에 남아 있는 정보를 기반으로 과거 시점의 데이터를 SELECT로 다시 조회한다는 점입니다.
즉, 실수로 데이터를 변경했을 때 바로 할 일은 무작정 다시 UPDATE를 치는 것이 아니라, 먼저 “실수하기 전 시점의 데이터가 아직 조회 가능한지” 확인하는 것입니다.
Flashback Query란?
Oracle Flashback Query는 특정 시점의 데이터를 조회할 수 있게 해주는 기능입니다.
일반적인 SELECT는 현재 시점의 데이터를 조회합니다.
SELECT *
FROM TB_X;
하지만 Flashback Query를 사용하면 다음처럼 과거 시점의 데이터를 조회할 수 있습니다.
SELECT *
FROM TB_X AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE);
위 쿼리는 TB_X 테이블을 현재가 아니라 30분 전 시점 기준으로 조회합니다.
이 기능은 실수로 데이터가 변경되었을 때 특히 유용합니다.
예를 들어 10시 30분에 이벤트 페이지 데이터가 삭제되었고, 10시 20분에는 데이터가 정상 상태였다는 것을 알고 있다면 10시 20분 기준의 데이터를 조회해서 현재 데이터와 비교하거나, 필요한 행만 다시 복구할 수 있습니다.
운영 환경에서는 이런 차이가 큽니다. 단순히 “예전 데이터를 볼 수 있다”가 아니라, 장애 영향이 커지기 전에 정상 시점의 데이터를 빠르게 확인하고 복구 근거를 확보할 수 있기 때문입니다.
AS OF TIMESTAMP와 AS OF SCN의 차이
Flashback Query에서 과거 시점을 지정하는 방식은 크게 두 가지입니다.
첫 번째는 시간 기준입니다.
SELECT *
FROM TB_X AS OF TIMESTAMP TO_TIMESTAMP('2026-05-06 10:20:00', 'YYYY-MM-DD HH24:MI:SS');
또는 현재 시각을 기준으로 상대 시간을 지정할 수도 있습니다.
SELECT *
FROM TB_X AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE);
두 번째는 SCN 기준입니다.
SELECT *
FROM TB_X AS OF SCN 123456789;
SCN은 System Change Number의 약자로, Oracle이 데이터베이스 변경 이력을 관리하는 내부 번호입니다. 사람이 보기에는 TIMESTAMP 방식이 더 직관적이지만, DB 내부적으로는 SCN이 더 정확한 기준이 됩니다.
운영 중 빠르게 확인할 때는 AS OF TIMESTAMP가 편합니다. 반면 장애 분석이나 특정 변경 지점을 더 정확히 추적해야 한다면 AS OF SCN을 사용하는 편이 좋습니다.
실수로 UPDATE한 데이터를 확인하는 패턴
예를 들어 이벤트 페이지의 노출 상태나 종료 여부가 잘못 변경되었다고 가정해보겠습니다.
UPDATE TB_EVENT
SET USE_YN = 'N'
WHERE EVENT_ID = 'EVT_20260506';
문제는 조건이 충분히 좁혀지지 않아 원래 비노출 처리되면 안 되는 이벤트까지 함께 변경된 상황입니다.
이때 바로 다시 UPDATE를 실행하면 위험합니다. 먼저 과거 시점의 데이터를 조회해야 합니다.
SELECT *
FROM TB_EVENT AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE)
WHERE EVENT_ID = 'EVT_20260506';
현재 데이터와 과거 데이터를 비교하려면 같은 테이블을 현재 시점과 과거 시점으로 나누어 조회할 수 있습니다.
SELECT
cur.EVENT_ID,
cur.EVENT_TITLE AS CURRENT_TITLE,
old.EVENT_TITLE AS OLD_TITLE,
cur.USE_YN AS CURRENT_USE_YN,
old.USE_YN AS OLD_USE_YN,
cur.START_DATE AS CURRENT_START_DATE,
old.START_DATE AS OLD_START_DATE,
cur.END_DATE AS CURRENT_END_DATE,
old.END_DATE AS OLD_END_DATE
FROM TB_EVENT cur
JOIN TB_EVENT AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE) old
ON cur.EVENT_ID = old.EVENT_ID
WHERE cur.EVENT_ID = 'EVT_20260506'
AND (
cur.USE_YN <> old.USE_YN
OR cur.EVENT_TITLE <> old.EVENT_TITLE
OR cur.START_DATE <> old.START_DATE
OR cur.END_DATE <> old.END_DATE
);
이렇게 하면 현재 이벤트 데이터와 30분 전 이벤트 데이터 중 달라진 값을 확인할 수 있습니다.
복구 전에 반드시 이 비교 과정을 거치는 것이 좋습니다. Flashback Query는 강력하지만, 복구 UPDATE나 INSERT를 잘못 작성하면 두 번째 장애를 만들 수 있기 때문입니다.
삭제된 이벤트 페이지를 복구하는 기본 패턴
가장 자주 쓰이는 패턴은 실수로 삭제된 데이터를 다시 INSERT하는 방식입니다.
이벤트 페이지처럼 광고사에 이미 URL이 배포된 데이터는 복구 속도도 중요하지만, 원래 내용 그대로 복구하는 것이 더 중요합니다. 제목, 본문, 노출 기간, 참여 조건, 이미지 경로, 상태 값 등이 조금만 달라도 사용자 안내가 달라질 수 있기 때문입니다.
예를 들어 특정 조건의 데이터가 잘못 삭제되었다면, 과거 시점의 데이터를 조회해서 현재 테이블에 다시 넣을 수 있습니다.
INSERT INTO TB_X
SELECT *
FROM TB_X AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE)
WHERE 조건;
이 방식은 단순하지만 실무에서는 주의할 점이 있습니다.
첫째, 현재 테이블에 이미 같은 PK 데이터가 존재하면 INSERT가 실패할 수 있습니다.
둘째, 과거 시점의 전체 데이터를 무조건 넣으면 정상적으로 변경된 데이터까지 되돌릴 수 있습니다.
셋째, 복구 대상 컬럼과 현재 테이블 컬럼 구조가 정확히 일치해야 합니다.
그래서 실무에서는 바로 INSERT하기보다 먼저 복구 대상만 별도 테이블로 백업해두는 방식이 안전합니다.
CREATE TABLE TB_X_RECOVERY AS
SELECT *
FROM TB_X AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE)
WHERE 조건;
그다음 복구 대상 건수를 확인합니다.
SELECT COUNT(*)
FROM TB_X_RECOVERY;
그리고 현재 테이블과 비교합니다.
SELECT r.*
FROM TB_X_RECOVERY r
LEFT JOIN TB_X cur
ON r.ID = cur.ID
WHERE cur.ID IS NULL;
최종적으로 현재 테이블에 없는 데이터만 넣습니다.
INSERT INTO TB_X
SELECT r.*
FROM TB_X_RECOVERY r
LEFT JOIN TB_X cur
ON r.ID = cur.ID
WHERE cur.ID IS NULL;
이렇게 하면 이미 존재하는 데이터와 충돌할 가능성을 줄일 수 있습니다.
잘못 UPDATE된 데이터를 되돌리는 패턴
DELETE 복구는 과거 데이터를 다시 INSERT하는 방식이지만, UPDATE 복구는 현재 행을 과거 값으로 다시 갱신하는 방식입니다.
예를 들어 이벤트 페이지의 노출 상태, 제목, 노출 기간이 잘못 변경되었다면 다음처럼 복구할 수 있습니다.
MERGE INTO TB_EVENT cur
USING (
SELECT
EVENT_ID,
EVENT_TITLE,
USE_YN,
START_DATE,
END_DATE
FROM TB_EVENT AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '30' MINUTE)
WHERE EVENT_ID = 'EVT_20260506'
) old
ON (cur.EVENT_ID = old.EVENT_ID)
WHEN MATCHED THEN
UPDATE SET
cur.EVENT_TITLE = old.EVENT_TITLE,
cur.USE_YN = old.USE_YN,
cur.START_DATE = old.START_DATE,
cur.END_DATE = old.END_DATE;
전체 컬럼을 되돌리는 것보다, 실제로 잘못 변경된 컬럼만 지정해서 복구하는 편이 안전합니다.
운영 환경에서는 같은 테이블이라도 사고 이후 정상적으로 변경된 컬럼이 있을 수 있습니다. 따라서 “행 전체를 과거로 되돌리는 것”보다 “문제가 된 컬럼만 되돌리는 것”이 더 현실적인 복구 방식입니다.
AS OF TIMESTAMP를 사용할 때 주의할 점
Flashback Query는 마법 같은 기능이지만, 아무 때나 과거 데이터를 조회할 수 있는 것은 아닙니다.
가장 중요한 제약은 UNDO_RETENTION입니다.
Flashback Query는 UNDO 데이터를 기반으로 과거 시점의 데이터를 재구성합니다. 따라서 UNDO 영역에 해당 시점의 정보가 남아 있어야 합니다.
예를 들어 UNDO 보존 시간이 15분 수준인데 2시간 전 데이터를 조회하려고 하면 실패할 수 있습니다.
SELECT *
FROM TB_X AS OF TIMESTAMP (SYSTIMESTAMP - INTERVAL '2' HOUR);
이 경우에는 다음과 같은 오류를 만날 수 있습니다.
ORA-01555: snapshot too old
이 오류는 과거 시점 데이터를 재구성하는 데 필요한 UNDO 정보가 이미 덮어써졌거나 부족할 때 발생할 수 있습니다.
따라서 Flashback Query를 복구 수단으로 활용하려면 운영 DB의 UNDO 설정과 트래픽 특성을 함께 이해해야 합니다.
DDL 이후에는 왜 조심해야 할까?
Flashback Query는 주로 DML 변경을 되돌리는 데 유용합니다.
DML은 다음과 같은 작업입니다.
INSERT
UPDATE
DELETE
반면 DDL은 테이블 구조 자체를 변경하는 작업입니다.
ALTER TABLE
TRUNCATE TABLE
DROP TABLE
Flashback Query는 UNDO를 기반으로 과거 데이터를 조회하는 기능이기 때문에, 테이블 구조가 바뀌었거나 TRUNCATE처럼 데이터를 빠르게 제거하는 작업이 수행된 경우에는 일반적인 AS OF TIMESTAMP 방식으로 복구하기 어렵습니다.
특히 TRUNCATE는 DELETE와 다르게 각 행을 하나씩 삭제하는 방식이 아니라 테이블 세그먼트를 초기화하는 성격이 강합니다. 그래서 실수로 TRUNCATE를 실행했다면 일반적인 Flashback Query 복구 패턴을 기대하면 안 됩니다.
DROP TABLE의 경우에는 별도의 Flashback Drop 기능을 사용할 수 있습니다.
FLASHBACK TABLE TB_X TO BEFORE DROP;
이 기능은 UNDO가 아니라 Oracle Recycle Bin에 남아 있는 정보를 이용합니다. 따라서 휴지통 기능이 비활성화되어 있거나, 이미 purge된 경우에는 사용할 수 없습니다.
운영 사고 상황에서 안전하게 사용하는 순서
이벤트 페이지 삭제처럼 영향도가 큰 운영 사고가 발생했을 때는 다음 순서로 접근하는 것이 좋습니다.
첫째, 추가 변경을 멈춥니다.
실수한 테이블에 대해 다시 UPDATE나 DELETE를 반복하면 복구 범위가 더 복잡해집니다.
둘째, 사고 시점을 특정합니다.
정확히 몇 시 몇 분에 문제가 발생했는지 확인해야 합니다. 이벤트 페이지가 삭제된 시간, 운영팀 작업 시간, 관리자 페이지 로그, DB 실행 이력 등을 함께 봐야 합니다.
셋째, Flashback Query로 과거 데이터를 조회합니다.
SELECT *
FROM TB_X AS OF TIMESTAMP TO_TIMESTAMP('2026-05-06 10:20:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE 조건;
넷째, 현재 데이터와 과거 데이터를 비교합니다.
SELECT
cur.ID,
cur.STATUS AS CURRENT_STATUS,
old.STATUS AS OLD_STATUS
FROM TB_X cur
JOIN TB_X AS OF TIMESTAMP TO_TIMESTAMP('2026-05-06 10:20:00', 'YYYY-MM-DD HH24:MI:SS') old
ON cur.ID = old.ID
WHERE cur.STATUS <> old.STATUS;
다섯째, 복구 대상 데이터를 별도 테이블로 먼저 백업합니다.
CREATE TABLE TB_X_RECOVERY AS
SELECT *
FROM TB_X AS OF TIMESTAMP TO_TIMESTAMP('2026-05-06 10:20:00', 'YYYY-MM-DD HH24:MI:SS')
WHERE 조건;
여섯째, 건수와 키 충돌 여부를 확인한 뒤 복구합니다.
SELECT COUNT(*)
FROM TB_X_RECOVERY;
마지막으로 복구 후 다시 검증합니다.
SELECT COUNT(*)
FROM TB_X
WHERE 조건;
이벤트 페이지라면 DB 복구만 확인하면 끝이 아닙니다. 실제 랜딩 URL 접근 여부, 이벤트 상태 값, 노출 기간, 이미지 또는 첨부 리소스 경로, 광고사에서 유입되는 링크 동작까지 함께 확인해야 합니다.
복구 작업은 빠르게 하는 것도 중요하지만, 더 중요한 것은 한 번 더 사고를 만들지 않는 것입니다.
Flashback Query를 믿되, 백업을 대체한다고 생각하면 안 된다
Flashback Query는 운영 중 발생한 논리적 실수를 빠르게 확인하고 복구하는 데 매우 유용합니다.
특히 다음 상황에서 효과적입니다.
- WHERE 조건을 잘못 작성한 UPDATE
- 일부 데이터를 실수로 DELETE한 경우
- 배치 실행 후 변경 전후 데이터를 비교해야 하는 경우
- 장애 원인을 추적하기 위해 특정 시점의 데이터를 확인해야 하는 경우
하지만 Flashback Query는 백업을 대체하지 않습니다.
UNDO 보존 기간이 지나면 조회할 수 없고, DDL 작업 이후에는 제한이 있으며, 대량 트랜잭션이 많은 환경에서는 필요한 UNDO 정보가 더 빨리 사라질 수 있습니다.
따라서 Flashback Query는 “운영 사고 직후 빠르게 확인하고 일부 데이터를 복구하는 도구”로 이해하는 것이 좋습니다.
장기적인 복구 전략은 RMAN 백업, 아카이브 로그, 복제 환경, 감사 로그, 변경 이력 테이블 같은 별도 체계와 함께 설계해야 합니다.
마무리
Oracle Flashback Query는 실수로 데이터를 변경했을 때 가장 먼저 떠올릴 만한 복구 도구입니다.
AS OF TIMESTAMP, AS OF SCN을 사용하면 UNDO 영역에 남아 있는 과거 시점 데이터를 조회할 수 있고, 이를 기반으로 잘못 삭제된 데이터를 다시 INSERT하거나 잘못 변경된 값을 UPDATE로 되돌릴 수 있습니다.
다만 핵심은 기능 자체보다 사용 순서입니다.
바로 복구 쿼리를 실행하기보다, 먼저 과거 데이터를 조회하고, 현재 데이터와 비교하고, 복구 대상을 별도 테이블로 분리한 뒤, 최소 범위로 복구해야 합니다.
운영 DB에서 중요한 것은 “되돌릴 수 있는 기능을 아는 것”보다 “되돌릴 때도 안전하게 되돌리는 절차를 갖는 것”입니다.
Flashback Query는 그 절차의 첫 번째 도구로 충분히 강력합니다.