개념: Soft Delete와 Hard Delete
Soft Delete는 데이터를 물리적으로 삭제하지 않고, 삭제된 것처럼 ‘표시’만 하는 전략입니다. DELETE 쿼리로 데이터를 완전히 제거하는 물리 삭제(Hard Delete)와 달리, Soft Delete는 UPDATE 쿼리를 사용해 특정 컬럼 값을 변경합니다.
deleted_at- 데이터가 삭제된 시점을 타임스탬프로 기록is_deleted- 삭제 여부를 나타내는 플래그(flag)를true로 변경
요약하면 Soft Delete는 ‘삭제’를 데이터 파괴(Destroy)가 아닌 상태 변경(State Change)으로 다루는 접근법이며, Hard Delete는 데이터를 영구적으로 제거하는 것을 목적으로 합니다.
Soft Delete의 장점과 목적
Soft Delete를 도입하면 다음과 같은 이점을 얻을 수 있습니다.
- 데이터 복구 및 안정성 확보 - 사용자의 실수나 애플리케이션 버그로 데이터가 삭제되더라도, 간단한
UPDATE쿼리 한 번으로 즉시 복구할 수 있어 데이터 유실에 대한 효과적인 안전장치가 됩니다. - 데이터 이력 추적 및 감사(Auditing) - 데이터의 생성, 수정뿐만 아니라 삭제 시점(
deleted_at)까지 모두 기록하여 데이터의 전체 생명주기를 추적할 수 있습니다. 이는 법적 규제 준수나 서비스 운영상 중요한 감사 로그로 활용됩니다. - 참조 무결성 유지 - 다른 데이터와 관계를 맺고 있는 데이터를 물리 삭제할 때 발생하는 복잡한 문제를 피할 수 있습니다. 예를 들어, 탈퇴한 회원이 작성한 게시글의 관계를 ‘탈퇴 상태’ 회원 레코드와 안전하게 유지할 수 있습니다.
- 통계 및 비즈니스 분석 - 삭제된 데이터를 보존함으로써, 서비스 개선을 위한 다양한 통계나 비즈니스 분석 자료로 활용할 수 있습니다.
Soft Delete의 단점과 비용
장점만큼 명확한 단점과 기술적 비용이 따릅니다.
- 쿼리 복잡성 증가 - 모든
SELECT쿼리에WHERE deleted_at IS NULL또는is_deleted = false조건을 항상 포함해야 합니다. 이 조건을 누락하면 삭제된 데이터가 사용자에게 노출되는 심각한 버그로 이어질 수 있습니다. ORM의 Global Filter 등으로 자동화할 수 있지만, 이는 복잡성을 감출 뿐 근본적인 해결책으로 보기 어렵습니다. - 스토리지 비용 증가 - 데이터가 물리적으로 제거되지 않으므로 테이블과 인덱스의 크기가 계속 커져 스토리지 비용 부담으로 직결됩니다.
- 성능 저하 가능성 - 테이블이 비대해지면서 인덱스 효율이 떨어지고, 쿼리 시 스캔해야 할 데이터 양이 늘어나 전반적인 DB 성능 저하를 유발할 수 있습니다.
- 데이터 관리의 복잡성 - GDPR의 ‘잊힐 권리’ 등 법적 규제에 따라 데이터를 영구 삭제해야 할 경우, Soft Delete된 데이터를 다시 Hard Delete하는 별도의 배치(Batch) 로직을 구현해야 하는 이중 관리 부담이 발생합니다.
- Unique 제약 조건 문제 -
email컬럼에UNIQUE제약이 있는 상황에서 한 사용자가 탈퇴(Soft Delete)하면, 해당 이메일은 DB에 여전히 존재하므로 동일한 이메일로 재가입이 불가능합니다.UNIQUE제약 조건 위배 오류를 피하려면 복합 유니크 인덱스를 설정하거나 애플리케이션 레벨에서 복잡한 예외 처리가 필요합니다.
선택 기준: 언제 무엇을 써야 할까
어떤 전략을 선택할지는 “이 데이터가 유실되었을 때 비즈니스에 얼마나 치명적인가"라는 질문으로 결정할 수 있습니다.
✅ Soft Delete 권장 대상
- 핵심 비즈니스 데이터 - 복구 가능성이 조금이라도 있거나 데이터 관계 및 이력 추적이 중요한 경우
- 예시:
users(회원),products(상품),orders(주문),posts(게시물)
- 예시:
- 명확한 비즈니스 상태 표현 - ‘삭제’가 아닌 ‘탈퇴’, ‘판매 중지’, ‘주문 취소’ 등 명확한 비즈니스 ‘상태’로 관리되어야 하는 데이터
✅ Hard Delete 권장 대상
- 부가적인 임시성 데이터 - 유실되어도 서비스 운영에 지장이 없고 복구할 필요가 없는 경우
- 예시:
logs(단순 로그),temp_caches(임시 캐시),notification_reads(알림 읽음 상태)
- 예시:
- 법적/보안상 의무 - 법적 또는 보안상 이유로 데이터를 즉시 영구적으로 파기해야 하는 경우