업무 중 UPDATE·DELETE 한 방에 잘못 날리면 식은땀이 나죠.
이 글은 즉시 복구부터 사후 복구까지, 상황별 되돌리기(rollback) 방법을 한 번에 정리합니다.
SET XACT_ABORT ON; -- 오류 시 자동 롤백(권장)
BEGIN TRAN;
-- ✅ 여기부터 작업
UPDATE dbo.Orders
SET Status = 'Closed'
WHERE OrderDate < '2025-01-01';
-- ✅ 여기까지 작업
-- 점검
SELECT @@ROWCOUNT AS AffectedRows;
-- 확인 후 커밋/롤백
-- COMMIT;
-- ROLLBACK;
BEGIN TRY
BEGIN TRAN;
-- 위험 작업
DELETE FROM dbo.Logs WHERE LogDate < DATEADD(MONTH, -6, GETDATE());
COMMIT;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0 ROLLBACK;
THROW; -- 오류 재발생(로그/모니터링)
END CATCH
BEGIN TRAN;
UPDATE dbo.A SET Qty = Qty - 10 WHERE Id = 1;
SAVE TRAN sv1;
UPDATE dbo.B SET Qty = Qty + 10 WHERE Id = 2;
-- 문제 발견!
ROLLBACK TRAN sv1; -- B만 되돌림
COMMIT; -- A는 반영
-- 1) 백업
SELECT d.*
INTO dbo._bak_Product_20250922
FROM dbo.Product d WITH (HOLDLOCK, UPDLOCK) -- 동시변경 방지
WHERE Category = 'A';
-- 2) 변경 + 변경 전 값 저장
DECLARE @chg TABLE (PK int, OldPrice money);
UPDATE p
SET Price = Price * 1.1
OUTPUT inserted.Id, deleted.Price INTO @chg(PK, OldPrice)
FROM dbo.Product p
WHERE Category = 'A';
-- 3) 문제 시 되돌리기
-- UPDATE p SET Price = c.OldPrice
-- FROM dbo.Product p JOIN @chg c ON p.Id = c.PK;
-- 1) 삭제 대상 백업
SELECT d.*
INTO dbo._bak_OrderDetail_20250922
FROM dbo.OrderDetail d WITH (HOLDLOCK, UPDLOCK)
WHERE OrderDate < '2024-01-01';
-- 2) 삭제
DELETE FROM dbo.OrderDetail
WHERE OrderDate < '2024-01-01';
-- 3) 되돌리기(필요 시)
-- INSERT INTO dbo.OrderDetail ( ...컬럼목록... )
-- SELECT ... 동일 컬럼 ...
-- FROM dbo._bak_OrderDetail_20250922;
포인트
- OUTPUT/백업 테이블을 먼저 만들면 “수동 undo”가 쉬워집니다.
- 대용량은 TOP 10000 배치 + 야간 실행 추천.
DECLARE @newKeys TABLE (PK int);
INSERT dbo.UserPoint(UserId, Point, Memo)
OUTPUT inserted.Id INTO @newKeys
SELECT u.Id, 100, 'event'
FROM dbo.Users u WHERE u.IsActive = 1;
-- 문제 시
-- DELETE p FROM dbo.UserPoint p JOIN @newKeys k ON p.Id = k.PK;
BEGIN TRAN;
ALTER TABLE dbo.Customer ADD Phone2 VARCHAR(20) NULL;
-- 점검 후
-- COMMIT;
-- ROLLBACK; -- 일부 DDL은 롤백 가능/불가가 달라서 사전 테스트 필수
실무 팁
- 마이그레이션 도구(예: SSDT/DACPAC, EF Migrations)의 Down 스크립트를 반드시 관리.
- 프로시저/뷰 수정은 이전 버전 스크립트를 저장소에 보관.
-- 복구 예시(요지: 원하는 시각으로 STOPAT)
RESTORE DATABASE MyDB FROM DISK='full.bak' WITH NORECOVERY;
RESTORE LOG MyDB FROM DISK='log_2025_0922.trn'
WITH STOPAT = '2025-09-22T10:45:00', RECOVERY;
주의: DB 전체 시점 이동이라 운영에 영향 큼 → 보통 별도 복구용 DB로 리스토어 후, 차분 데이터만 추출/머지.
SELECT *
FROM dbo.Customer
FOR SYSTEM_TIME AS OF '2025-09-22 10:40:00'
WHERE Id = 1001;
→ 과거 스냅샷에서 값 조회 후 정상 테이블에 반영.