[개발/Spring] Soft delete vs Hard delete에 대한 나의 생각
resilient
·2023. 3. 29. 23:13
현업에서 개발을 하면서 깨달은 사실은 사소해 보이는 데이터 또한 소중한 자산이라는 점입니다.
따라서 추후에 다시는 사용하지 않거나 데이터 분석이 필요 없는 데이터들을 제외하고는 보통 DB에 남겨놓는 편인데요. 여기서 Soft delete(논리삭제)와 Hard delete(물리삭제)가 등장합니다.
이번 포스팅에서는 Soft delete, Hard delete에 대해서 살펴보고 제 생각을 간단하게 정리해보려고 합니다.
0. Soft delete(논리 삭제), Hard delete(물리 삭제) 란?
말 그대로 논리적으로만 삭제하는 방법입니다. 논리삭제를 해도 물리적인 데이터는 DB에 그대로 남아있게 됩니다.
먼저 물리 삭제 예시를 들어보겠습니다.
일반적인 삭제 Delete 쿼리는 아래와 같습니다. 쿼리를 실행하면 DB에서 물리적으로 사라지게 되죠.
이것이 물리삭제입니다.
DELETE FROM User WHERE userId = ?
위의 동작을 논리 삭제로 구현해보겠습니다.
UPDATE User SET activated = 0 where userId = ?
논리적인 개념의 컬럼을 추가하고 해당 컬럼을 UPDATE 실행을 하면 삭제되었다고 여기는 것입니다.
위의 예시에서는 activated 라는 활성화를 담당하는 컬럼을 추가했고 삭제 구현 시, activated = false(0)으로 표현해주는 것이죠.
1. Soft delete(논리 삭제)를 사용하는 이유 및 장점
논리선택을 하는 이유는 다음과 같습니다.
다양한 이유가 있겠지만 가장 우선적으로 떠오르는 것은 데이터가 유지되어야 하는 속성의 테이블의 경우에는 논리삭제로 해당 테이블 레코드의 가장 마지막 순간을 남겨놓는 것으로 생각됩니다.
예를 들어 유저가 삭제를 했지만 실수로 인한 삭제였을 시에, 복원이 가능해야 하는 도메인이 있습니다. Delete 쿼리보다 안전한 방법으로 써 유저들에게 제공하는 서비스의 질을 높일 수 있는 방법이기도 하죠.
또한 Update 쿼리가 Delete 쿼리보다 마이크로초 단위로 봤을 때 더 빠릅니다. 대량의 데이터 일경우에는 차이가 극대화될 수도 있죠.
마지막으로 처음에도 언급을 했지만 데이터는 소중하기 때문이죠. 유저들이 서비스를 사용하면서 쌓고 있는 많은 데이터들은 범법행위가 아닌 범위 내에서는 데이터 분석을 통해 마케팅 및 기획 개발에도 사용할 수 있습니다. 오늘날의 비즈니스에서 고려해야만 하는 포인트입니다.
2. Soft delete(논리 삭제)의 단점
단점 또한 명확한데요.
간단하게 생각하면 실제 Delete가 없고 Update만 일어나게 된다면 물리적으로 한번 쌓인 데이터는 삭제하지 못하는 구조이기 때문에 데이터베이스의 용량이 매우 커질 수밖에 없습니다. 이 데이터들 중에는 필요 없는 데이터들도 많을 수밖에 없죠.
또한 논리삭제는 애플리케이션 성능 측면에서 생각해 보면 DB 스키마 구조에서 불필요한 컬럼을 하나 차지하게 되므로 검색조건시에 삭제처리된 레코드의 경우 반드시 필터 해주어야 하기 때문에 SELECT 조회 시 불필요한 검색조건을 추가해야 합니다.
가장 치명적인 단점은 여러 개발자들이 참여하는 규모가 있는 프로젝트일 경우 where를 꼭 써야만 한다는 것입니다.
좋은 개발에서 중요한 요소 중 하나는 직관적이어야 한다는 것인데, where을 통한 필터링이 꼭 추가되어야 한다는 사실은 꽤나 직관적이지 않다고 볼 수 있습니다.
3. 그럼 언제 논리 삭제를 사용하고 물리삭제를 사용해야 할까?
여기서는 제 생각을 정리해보려고 합니다.
먼저 삭제가 되더라도 데이터가 남아있어야 할 법한 데이터들에 대해서는 논리 삭제를 사용하는 것이 좋습니다. 서비스를 운영하다 보면 유저들로부터 많은 컴플레인을 받게 되는데 그중 실수로 인한 삭제에 대한 상황에서의 대처를 유연하게 하려면 논리삭제를 사용하는 것이 좋아 보입니다.
반대로 테이블 안의 데이터들이 특정 상황에서만 필요하고 꼭 남기지 않아도 되는 경우 물리삭제를 사용하는 것이 좋습니다.
예시를 들어보겠습니다.
Circle엔티티와 User엔티티의 양방향 연관관계 매핑을 위한 UserCircle이라는 엔티티가 있다고 가정하겠습니다.
여기서 Circle과 User의 연관관계 매핑이 끊어졌을 경우 굳이 UserCircle속 데이터를 남겨둘 필요가 있을까요? 없습니다. 이러한 경우에는 과감하게 물리삭제를 사용하는 편이 좋다고 볼 수 있죠.
정리를 해보면 '서비스 운영에 따라 다를 수 있다'입니다.
이 부분은 기술적으로 더 나은 방법이 있다고 볼 수 없고 그때그때 필요한 상황에 따라서 논리 삭제 및 물리 삭제를 사용하는 편이 좋다고 할 수 있습니다.
4. Spring에서 Soft delete 사용 시 많이 사용하는 방법들
4-1. @SQLDelete
먼저 @SQLDelete 어노테이션이 있습니다.
JPA를 사용할 경우 ORM 레벨에서 Delete쿼리를 하나하나 Update로 바꾸는 것이 아닌 Delete 쿼리가 나갈 경우 자동으로 설정해 놓은 Update 쿼리로 대신 나가게 해주는 기능입니다.
아래와 같이 SQLDelete안에 Update 쿼리를 넣어주면 user_circle 엔티티 내에서 Delete 쿼리가 나가게 될 경우 작성한 Update 쿼리를 실행시켜 줍니다.
4-2. @Where
@Where 어노테이션은 Entity의 Default 조건을 지정할 수 있는 어노테이션입니다.
장점은 'Soft Delete'로 인하여, 객체 그래프에서 발생할 수 있는 문제를 신경 쓰지 않아도 된다는 점입니다.
아래와 같이 작성해 주면, Friend엔티티와 관련된 모든 동작들은 activated가 true(1)인 경우에만 동작을 하게 되죠.
하지만 @Where 어노테이션의 치명적인 문제가 있습니다.
프로젝트를 진행하다가 다음과 같은 상황을 마주했습니다.
'초대를 하면 activated가 0인 데이터가 만들어지고 수락을 하면 activated를 1로 바꾼다.'
여기서 @Where을 써버리면 유저가 해당 초대 수락을 위해 조회를 해야 하는데 할 수가 없게 되죠.
애초에 엔티티레벨에 @Where이라는 강력한 필터링을 붙여버리는 것부터 이게 최선인가.. 싶긴 합니다. 의존성이 너무 강력해서요.
그래서 등장한 @FilterDef라는 어노테이션이 있어서 필요에 따라 조건을 동적으로 추가할 수 있습니다. 하지만 공식문서를 찾아보니 설계를 이렇게 까지 바꿀 필요는 없다고 판단해서 사용하지 않았습니다.
해당 내용은 여기 블로그에 자세하게 나와있으므로 사용하실 분들은 참고하시면 좋을 듯합니다.
5. 정리
이번 포스팅에서는 Soft Delete와 Hard Delete에 대해서 알아보고 실제로 어떤 경우에 사용해야 효율적인 개발을 할 수 있는지 생각해 봤습니다.
현재 진행 중인 프로젝트에도 필요에 따라 Soft Delete와 Hard Delete를 구현해서 조금이라도 더 효율적인 DB관리를 해보려고 합니다.
감사합니다.
6. Reference
https://abstraction.blog/2015/06/28/soft-vs-hard-delete
https://www.becomebetterprogrammer.com/soft-delete-vs-hard-delete/#Are_Soft_Deletes_Bad
'글 > 개발' 카테고리의 다른 글
[개발] Pass By Value vs Pass By Reference 란? (0) | 2022.02.28 |
---|---|
[Git] Git rebase, Git squash로 커밋 정리하기 (0) | 2021.11.30 |
[개발]TDD / 테스트코드 란? (0) | 2021.08.10 |
[에러/삽질] vscode 에서 Delete `␍`eslintprettier/prettier 해결 (0) | 2021.08.08 |
[에러/삽질]Cannot use import statement outside a module 해결 (0) | 2021.08.01 |