⌨️ 순차적인 상황만 고려했었네...?
TODO 리스트
https://romanc3.tistory.com/56
2023.04.03 [PROJECT][TODO] Culinari V2 DB 최적화 및 고민
⌨️ DB 최적화 및 고민 미처 진행하지 못했던 DB의 최적화와 이해 그리고 고민 등을 이번 주, 길게는 2주에 걸쳐 진행 그리고 계속 늘어지는 일정 관리 때문에 약간은 스프린트 식으로 1주, 2주 단
romanc3.tistory.com
에서 JPA 연관 관계 매핑과 정규화 부분에 대한 고민을 하던 중 문득 이런 생각이 들었다.
너무 순차적으로만 생각하는데..? 부분 부분에 있어서 오류가 있을거 같다.
추상적인 생각이기에 마땅한 제목이 생각이 안나서 여러 번의 포스팅으로 정리하려 한다.
우선 생성과 수정 삭제 쪽을 먼저 작성하고 후에 조회를 작성하겠다.
1. 연관 관계가 있을 때 상품과 카테고리 생성/수정/삭제
상품을 등록하고 카테고리를 생성하고 하는 과정에서 일전에는 순차적인 흐름만 생각했다.
카테고리를 만들고 세부 카테고리를 만들고 상품을 등록하는 과정 말이다.
생성은 문제가 없지만 수정과 삭제 과정에서 문제가 발생한다.
1.1. Column을 FK로 가지고 있는 상황
현재 우리 프로젝트의 카테고리와 상품부분을 약식으로 표현했다.
각 테이블의 PK를 외래키로 가지지 않고 code라는 UK를 외래키로 가지게 했다
1.2. 수정/삭제 시에 문제
아주 당연하게도 수정과 삭제시에는 참조 무결성에 의해 에러가 발생한다.
예를 들어 세부카테고리를 수정/삭제시에 상품에서 참조하고 있으므로 에러가 발생할 것이다.
아주 당연하지만 우리가 놓친 부분이었다.
해당 부분은 아래와 같이 설정을 해주었어야 했다.
1) On Delete
Cascade : 부모 데이터 삭제 시 자식 데이터도 삭제
Set null : 부모 데이터 삭제 시 자식 테이블의 참조 컬럼을 Null로 업데이트
Set default : 부모 데이터 삭제 시 자식 테이블의 참조 컬럼을 Default 값으로 업데이트
Restrict : 자식 테이블이 참조하고 있을 경우, 데이터 삭제 불가
No Action : Restrict와 동일, 옵션을 지정하지 않았을 경우 자동으로 선택된다.
2) On Update
Cascade : 부모 데이터 업데이트 시 자식 데이터도 업데이트
Set null : 부모 데이터 업데이트 시 자식 테이블의 참조 컬럼을 Null로 업데이트
Set default : 부모 데이터 업데이트 시 자식 테이블의 참조 컬럼을 Default 값으로 업데이트
Restrict : 자식 테이블이 참조하고 있을 경우, 업데이트 불가
No Action : Restrict와 동일, 옵션을 지정하지 않았을 경우 자동으로 선택된다.
첫째로 수정에선, 카테고리의 정보가 바뀌면 Cascade로 생명주기를 같이 가져가면 될 것이다. 정보의 업데이트를 통해 무결성을 맞춰주고
두번째로 삭제에선, Set null을 해줬어야 했다. 아직 프로젝트에 카테고리와 상품의 CUD가 없어 적용은 하지 않았지만, 이 부분을 고려해서 서비스를 추가하려 한다
(여담이지만, 이렇게 조금씩 생각나는 걸 하나하나씩 수정해나가다 보면 퀄리티가 꽤 좋아지지 않을까 한다 그렇기에 계획한 타임라인에 이러한 인사이트들을 더해서 리팩토링 해볼 생각이다. 우선 순위는 애석하게도 인사이트 쪽이다.. 아무래도 나는 계획한 것을 고려하는 것보다 그때 그때 떠오른 궁금증을 해소하는게 우선인 사람인거 같다.)
2. 연관 관계가 있을 때 상품의 조회
위와 같은 그림에서 연관 관계가 있을 때 상품의 조회는 일반적으로 가장 부모 테이블에서 참조를 활용한 조인을 통해 탐색해 나갈 것이다 즉 JPA를 활용하여 A에서 D까지 조인하여 탐색을 한다.
이 경우 쿼리문이 굉장히 무거워 질 것이다.
A->B->C->D 의 연관 관계를 가지고 있다면 우리는 D를 탐색하기 위해 A에서 B-C를 지나야 한다.
우선 우리 프로젝트에서 나는 해당 부분을 B에서 D를 바로 접근 할 수 있게 해서 해결했다.
대신 해당 방식은 Repository의 갯수를 늘린다.
그럼에도 불구하고 그러한 방식을 채택한 이유는 B의 값으로 D에 대한 접근이 많기 때문이었다.
Repository를 하나 더 늘리더라도 쿼리문을 조금 더 가볍게 하자는게 내 생각이었다.
3. 연관 관계가 없을 때 상품과 카테고리 생성/수정/삭제
이게 무슨 말인가? 연관 관계가 없다니..? 조금 더 고민을 해봐야겠지만
우선 내가 생각해낸 방법은 이거다. 조회만을 위한 중복 테이블 생성이다. (혹은 연관관계가 없는 테이블?)
연관 관계를 아예 끊은 채로 생각해봤지만, 그렇게 한다면 ERD를 보기가 더욱 힘들어질 것이다. 그렇기에 조회가 굉장히 많이 발생하는 상품 테이블에 대한 중복 테이블을 생성하여 조회만을 위해 활용 해보는 것이 어떨까 하는 생각이었다.
위 그림과 같이 말이다. 카테고리와 세부카테고리 쪽은 그렇게 많은 조회가 일어나지 않기에 우선은 상품에만 집중하였다.
쓰기에서 손해를 보지만, 쓰기보다 읽기가 월등히 많은 웹상황에서는 고려해봄직 하지 않은가?
접근 방법은 이렇다. product에 연관관계로 FK를 가지는 것이 아닌 직접 입력 한 카테고리와 세부 카테고리를 작성하여 생성하는 것이다.
생성은 그렇다 쳐도 수정 삭제는 ??
카테고리와 세부카테고리의 수정 삭제 시에, 개발자가 직접 product 테이블의 생명주기를 맞춰주어야 한다.
예를 들어 세부 카테고리를 수정할 때 product 테이블의 내가 수정 할 값을 가지고 있는 칼럼들의 값을 다 바꿔 준다든지 말이다.
3. 연관 관계가 없을 때 상품과 카테고리 조회
사실 이거 하나를 위해 위의 생성/수정/삭제를 희생했다고 봐도 무방하다.
방법은 이렇다.
내가 선택한 카테고리의 code를 가지고 product에 select를 날리는 것이다.
이 방법은 SELECT를 한번 더 날려야 한다는 단점이 있으나, 이러한 관점을 봤다.
생각보다 SELECT 한번 더 날리는 것은 큰 손해가 아니다.
그러한 관점에서 고안해낸 방식이다.
이 방식의 장점은 대신 테이블의 연관관계의 깊이가 아무리 깊더라도 단순한 SELECT의 연속이기 때문에 굉장히 빠르다.
3. 피드백
- 기존 방식에서 카테고리와 상품의 CUD 구현
- 다른 방식으로 구현한 것도 준비 -> 기존 서비스에서 변경 할 지 새로 프로젝트를 만들어서 확인할 지..
변인 통제를 위해 기존 서비스를 리팩토링 해야 하나 많은 노력이 필요해 보임 - 작성하고 고민한 것들을 뒷받침 할 정량지표를 만들어서 신뢰성 높히기
-> 생각만은 누구나 한다 생각한 것을 적용하고, 비교하고 그 결과를 직접 확인해야 호소력이 있다.
이 부분이 중요한데,
이러한 고민은 분명 좋은 접근 방식이다. 스스로는 그렇게 생각하나 뒷심이 딸린다.
무슨 말이냐면 내가 고민한 것을 코드로 구현하고 뒷받침 할 정량 지표가 없다는 것이다.
그렇기에 후에 이러한 고민들을 비교하여 쿼리문의 성능이나 조회 속도 등을 증명할 근거를 만들어봐야겠다