Hacker News 의견들
  • 내가 일하는 은행 도메인에서는 오히려 soft delete가 유리하다고 느꼈음
    deleted_at 컬럼이 있으면 쿼리 작성이 명확하고, 분석용 쿼리나 관리자 페이지에서도 동일한 데이터셋을 다룰 수 있음
    삭제는 대부분의 경우 드물고, soft delete된 행이 성능 문제를 일으킨 적도 거의 없었음
    또한 관계가 그대로 유지되므로 복구(undo) 도 간단함
    나는 더 나아가 행을 완전히 불변(immutable) 하게 만들어 업데이트 시 새 행을 추가하는 방식을 선호함
    로그를 남기려면 DB 트리거를 이용해 INSERT/UPDATE/DELETE 시 복제 테이블에 기록을 남기는 접근이 좋다고 생각함

    • 네 말이 맞지만, 삭제가 드문 경우에만 해당된다고 봄
      내가 본 테이블 중 50~70%가 soft delete된 경우에는 성능 저하가 확실히 있었음
      결국 soft delete는 상황에 따라 다르고, 사전 분석이 필요함
    • Postgres에서는 soft delete되지 않은 데이터만 인덱싱하도록 설정할 수도 있음
      대부분의 경우 필요 없지만, RAM 절약에는 도움이 될 수 있음
    • 은행에서 soft delete는 감사 추적성(auditability) 부족을 임시로 가리는 해결책에 불과함
      진짜 해법은 Event Sourcing으로, 모든 변경을 이벤트로 기록해야 함
      성능은 떨어지지만, 스냅샷과 동기화(sync) 로 보완 가능함
    • DB를 불변 구조로 운영하려면 Datomic 같은 시스템을 고려할 만함
      시간여행(time travel) 기능으로 과거 상태를 완전하게 조회할 수 있음
    • 예전 보험사에서 근무할 때도 각 테이블을 append-only 로그로 운영했음
      최신 상태는 가장 큰 타임스탬프의 행에 있고, 과거 상태는 필터로 조회 가능했음
      이 방식은 강력한 이력 관리를 가능하게 함
  • soft delete의 가장 큰 함정은 쿼리 복잡도
    처음엔 WHERE deleted_at IS NULL만 추가하면 된다고 생각하지만, 몇 달 지나면 필터 누락으로 유령 데이터가 보고서에 등장함
    View로 해결할 수 있지만, 결국 병렬 접근 패턴을 유지해야 하고, 삭제된 데이터 조회 시엔 추상화를 우회해야 함
    Event sourcing이 더 깔끔하지만 운영 부담이 크기 때문에, 대부분은 하이브리드 접근을 택함

    • View는 충분히 강력한 도구임
      문제는 많은 SWE와 BI 엔지니어가 SQL과 스키마 설계에 익숙하지 않다는 점임
      soft delete보다 더 흔한 문제는 Type 2 Slowly Changing Dimension 처리임
      대부분 불필요하게 audit table을 만들어 비효율적인 UPDATE/INSERT를 반복함
      사실 DB는 정말 아름다운 시스템인데, 그만큼 존중받지 못함이 아쉬움
  • soft delete가 DB 내장 기능으로 제공되면 좋겠다고 생각함
    테이블 단위로 활성화하고, 삭제 처리 전략을 선택할 수 있다면 이상적일 것 같음

    • 실제로 Iceberg, Delta Lake, BigQuery 같은 시스템은 time travel 기능을 제공함
      하지만 많은 팀이 커스텀 요구사항 때문에 결국 SCD(Slowly Changing Dimension) 방식으로 구현함
  • 내 경험상 트리거 기반 접근이 가장 안정적이었음
    아카이브 테이블은 append-only로 유지하고, 복구는 애플리케이션 레이어에서 처리해야 함
    업데이트는 soft delete로 간주하고, 트리거가 이전 상태를 캡처하도록 함
    트리거는 반드시 BEFORE 시점에 실행되어야 하며, 로직은 단순해야 함
    파티션은 월 단위가 일반적이고, 쓰기 부하가 많으면 일 단위로 나누는 게 좋음

  • 나는 DB가 stateful → stateless로 진화하길 바람
    모든 변경을 append-only 이벤트로 기록하고, 필요한 데이터는 view로 표현하는 구조를 선호함
    DB가 자동으로 materialized index를 관리해주면 이상적임
    일부 최신 DB는 이런 기능을 제공하지만, 아직은 OLTP 중심의 발전이 부족함

  • 예전에 다닌 회사에서는 모든 시스템에 soft delete를 적용했었음
    교수님도 “비즈니스 세계에서는 데이터가 절대 삭제되지 않는다”고 하셨던 게 기억남

    • 완전 삭제는 미래의 데이터 분석 능력을 스스로 제한하는 행위임
      저장 공간은 싸니까, 데이터를 절대 지우지 말아야 함
    • 하지만 수정에 대해서는 교수님이 아무 말도 안 하셨던 게 흥미로움
  • 데이터베이스는 사실(fact) 을 저장하는 곳임
    레코드 생성은 새로운 사실, 삭제는 또 다른 사실임
    하지만 행을 물리적으로 지우면 사실이 사라짐
    대부분의 경우 이런 삭제는 바람직하지 않음

    • 하지만 데이터가 유출 위험을 가진 자산이라면, 오히려 대량 삭제가 필요할 수도 있음
      유지 비용과 보안 리스크를 고려해야 함
    • DB가 불변이 아니라면, 수정 자체가 이미 사라진 사실을 만드는 셈임
      데이터를 영구 보존하는 결정은 신중해야 함
    • 개인적으로는 데이터 저장소가 조회와 삽입 두 가지 연산만 지원해야 한다고 생각함
      이를 위해 데이터의 수명 주기를 이해하는 것이 중요함
  • Firezone에서는 처음에 soft delete를 감사 로그용으로 썼지만, 마이그레이션 문제로 포기했음
    대신 Postgres CDC(Change Data Capture) 를 사용해 별도의 쓰기 최적화 테이블로 이벤트를 내보내는 방식으로 전환함
    soft delete는 사용자 복구 기능에는 유용하지만, 감사나 규정 준수 용도로는 부적절하다고 생각함

    • 단순한 프로젝트에서는 DB 변경 대신 API 호출 자체를 감사하는 게 더 효율적임
  • soft delete 필드를 가진 테이블 위에 View를 만들어, 삭제된 행을 숨기는 방식이 깔끔함
    이렇게 하면 애플리케이션은 삭제 여부를 신경 쓸 필요가 없음

    • Postgres의 RLS(Row Level Security) 를 이용하면 soft delete된 행을 자동으로 숨길 수 있음
      애플리케이션은 여전히 동일한 테이블에 읽기/쓰기/삭제를 수행함
  • 스키마 드리프트(schema drift) 는 어떻게 처리하냐는 질문이 있음
    삭제 당시의 스키마로 직렬화된 데이터를 나중에 복원하려면, 스키마 변경이 문제됨

    • 내 경험상 아카이브된 객체는 거의 접근되지 않음
      삭제 후 며칠 내 복원하는 경우가 대부분이라 스키마 변경 영향이 적음
      오래된 아카이브를 새 모델로 마이그레이션하는 건 복잡하고 오류 가능성이 높은 작업이었음
      결국 시스템의 사용 방식에 따라 접근 전략이 달라짐