오늘은 교보문고 온라인 쇼핑몰 ERD를 설계해보았습니다.
참고로 category_key와 category_id를 혼용해서 쓰고 있는데 여기서는 같은 의미입니다.
교보문고 카테고리를 보면 대분류, 중분류, 소분류로 나눠져있는 것을 확인할 수 있습니다.
국내도서, 서양도서, 일본도서는 대분류이고, 각 대분류밑에는 각각의 중분류가 존재하고, 그 밑에는 각각의 소분류가 있습니다.
처음에는 이 아이디어로 접근을 하였습니다. 각 상품마다 대분류, 중분류, 소분류 id를 받고 이에 해당하는 대분류 테이블, 중분류 테이블, 소분류 테이블을 두려고 하였습니다.
이 경우에는 소분류에 해당하는 상품들을 모두 가져오기는 편합니다.
그렇지만 치명적인 단점이 있습니다. 만약 소분류밑에 하나 더 분류(편하게 소소분류라고 하겠습니다.)를 넣는다면 Product 테이블에 소소분류 컬럼을 하나 더 만들어야합니다. 또한 이에 매핑되는 소소분류 테이블도 만들어야합니다. 그렇기때문에 유지보수에 매우 안 좋습니다.
책을 예를 들어서 생각해보겠습니다. 820번이라는 category_id를 갖는다면 맨 앞의 8은 대분류이고, 2는 중분류이고, 3은 소분류입니다.
이제 더이상 Product 테이블에서 대분류 id, 중분류 id, 소분류 id를 가지고 있을 필요가 없습니다.
그렇지만 이 경우에는 또 큰 문제가 있습니다. 분류들끼리의 부모 자식 관계를 알 수 없다는 것입니다.
부모와 자식의 관계가 매우 명확하기 때문에 대분류와 중분류, 소분류는 서로 연관이 되어있어야합니다.
물론 이 경우 중분류와 소분류에 parent_key를 넣어서 해결은 할 수 있지만 매우 복잡하게 됩니다.
그렇다면 어느 방법이 제일 좋을까요?
결론입니다.
Product 테이블에서는 category_key만 가지고 있고, Category 테이블에서는 대분류, 중분류, 소분류할 것 없이 모든 카테고리에 대해 가지고 있으면 됩니다. 예를 들면, Category 테이블에는 국내도서, 소설, 한국소설들이 전부 들어있게 되는거죠. 그렇다면 중분류였던 소설이 국내도서의 소설인지 외국도서의 소설인지 어떻게 알 수 있을까요?
-> parent_key 로 부모를 찾아갈 수 있겠죠
이 경우에는 소분류밑에 소소분류를 추가하기도 편합니다. 그래서 유지보수 측면에서 카테고리 테이블을 하나만 두도록 설계하였습니다.
그러다 문득 이런 생각이 들었습니다. 자식에서 부모를 알고 타고 올라가는 것은 충분히 좋은 설계인건 맞지만 만약 대분류인 국내도서 목록을 원한다면 어떻게 할까?
이에 대해 한동안 혼란을 겪던 중 팀원분이 소중한 참고자료를 보내주셨습니다.
계층이 있는 카테고리는 recursive하게 작성하는게 좋다는 것을 이해했습니다. 그렇지만 봐도 봐도 너무 비효율적일 것 같았습니다.
카테고리 테이블을 가서 재귀를 하든 중, 소 테이블에 가서 해당되는 카테고리들을 다 가져오든 어쨌든 카테고리 테이블을 거쳐야하는데, 굳이 그러지말고 category_id자체에 이게 국내도서인지, 국내도서의 소설인지 확인할 수 있게 id를 명명하는 규칙을(국내도서소설: KOR01.. 국내도서 시/에세이:KOR02) 우리끼리 정하면 굳이 카테고리 테이블을 안 들리고 product테이블에서의 연산만으로도 그 카테고리에 해당하는 데이터들을 가져오게 하면 되지 않을까..?
그럼 이 경우에는 category_id 자체에 부모가 명시적으로 드러나니 굳이 재귀패턴을 안 써도 되지않을까요?
그래서 id가 좀 길어지더라도 KOR01AB... 이런 식으로 적기로 하였습니다. 이렇게 하면 국내도서를 찾을 때 product 테이블에서 KOR%인 것들을 전부 불러오면 되겠죠?
이 모든 것은 집단 지성을 이용한 뇌피셜이고, 틀릴 수도 있으며 더 효율적인 방법이 있을 수도 있습니다. 만약 있다면 댓글로 알려주세요...!
like 절은 index를 사용하지 않기 때문에 대부분의 경우 사용하지 않는게 좋습니다.
초안대로 구성하는 것이 옳은 방식이고 굳이 최소한의 쿼리로 해결하고 싶다면 중첩 세트 모델을 사용하는 방법도 있습니다만, 무결성 해결이 어렵고 데이터 수정에 더 많은 비용이 발생합니다.
쿼리가 많아진다고 해서 무조건 안좋은건 아닙니다.
다만, 쿼리가 1개지만 index를 사용하지 않는다면 좋지 않습니다.
참조:
중첩 세트 모델: https://en.wikipedia.org/wiki/Nested_set_model
같이 보기: https://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/