DB 스키마 작성하는데 3일이 소요되었다. 처음에 한 3시간 정도면 되겠지라고 생각하였던게 큰 오산이였다.
처음에 필요한 테이블을 생각하였다. 그 다음에 각 테이블마다 어떤 필드가 필요할지 작성했다. 그런데!!!😱 그렇게 하니 이 테이블에 이 값이 들어가는 것이 맞는지? 아니면 또 다른 테이블을 만들어야 하는지?에 대해서 문제를 봉착하였다.🥺
필자의 경우, 클래스의 콘텐츠는 클래스 소개, 커리큘럼, 강사 소개 이렇게 3개의 값으로 나뉜다. 그런데 이 3개의 값 역시 또 다른 하위 값을 갖는다. 특히 클래스 소개 같은 경우 여러개의 이미지가 들어가고 그에 맞는 글이 들어가야하는 상황이다. 여기에서 가장 고민을 했던 부분은 강사 사용자가 글을 작성하고 이미지를 삽입하는 순서와 동일한 순서로 데이터가 심어져야한다...였다..
✋ 문제
- 여러 개의 이미지를 한 테이블에 넣어야 하나? 이미지1, 이미지2 이런식으로?? 아니면 값을 배열로 넣나??
- 여러 개의 이미지에 대응하는 글 들은 어떻게 저장하나?
- 그 이미지와 글들을 어떻게 순서대로 렌더링 시킬 것인가?
꼬리의 꼬리를 무는 질문들이 내 머리속에 가득찼다.
그래서 우선 가장 기본적인 것, DB 모델링을 어떻게 하는지 부터 유투버에서 찾아보았다.
참고 영상 링크
MySQL - 데이터 모델 설계, 실무에서는 이렇게 프로젝트 시작과 설계를 한다!
위 영상을 토대로 DB모델링에 대해 정리하자면 이와 같았다.
✍ DB 모델링 과정
- 1단계: 개념적(conceptual, contextual) 모델링 -> Entiti 도출
- 2단계: 논리적(Logical) 모델링
-> Data 구조 및 속성 정의
-> 무결성 정의 및 정규화(데이터의 중복을 최소화하는 것)
- 3단계: 물리적(Physical) 모델링
-> 실제로 코드화 하는 것
정규화의 목적, 목표
"중복 데이터를 없애고 관계를 단순하게 가져 간다!"
-
원자성
모든 속성은 하나의 값만 갖는다.
예) '특정 클래스'에 강사 '김코딩, 박해커' (X)
-
부분 종속 제거
모든 속성은 기본키에 종속되어야 한다.
예) '클래스'에 강사 연락처
-> 강사 연락처는 강사에 종속이다. (클래스의 종속 X)
-
이행 종속 제거
기본키가 아닌 모든 속성 간에는 서로 종속될 수 없다.
예) 우편번호와 기본 주소
-
BCNF
모든 결정자는 후보키에 속해야 한다.
(후보키: 각 행을 유일하게 식별할 수 있는 최소한의 속성들의 집합. 유일성과 최소성을 동시에 만족)
2. 모델링 기법 팁
- PK(기본키_유일값을 갖는 기본키 필수)가 중요하다.
- 적절한 정규화 하자!
원자성을 준수하고 최대한 중복 데이케가 없도록 한다.
계산 결과 컬럼을 최대한 자제
Nullable 할 필요가 없다면 Not Null로 하자!
- 참조 무결성을 위해 FK를 정의한다
예) '클래스'테이블과 '강사'테이블
강사가 없어졌는데 물건이 없어지면 안 됨
(데이터 무결성 data integrity: 데이터의 정확성과 일관성을 유지하고 보증하는 것)
- 서로 다른 성격의 컬럼들은 테이블 분리!
클래스 소개 콘텐츠는 클래스 소개글, 커리큘럼, 강사소개로 나뉨으로 분리한다
위의 단계로 필자의 프로젝트 DB 모델링을 해보았다.
✍ DB 모델링 구현
1. Entities(Object) 도출
Entities
- 일반사용자, 강사
- 클래스
- 동영상
- 커리큘럼
- 관심 클래스
- 구매한 클래스
- 개설 클래스
- 리뷰
- 리뷰 이미지
- QnA
Behavior
- 일반 사용자, 강사 관리자 로그인 / 회원가입 / 개인정보수정
- 클래스 개설 신청
- 클래스 동영상 업로드
- 클래스 구매
- 클래스 찜
- 클래스 리뷰
- 클래스 QnA
- 강사 지원
2. 관계설정
조인테이블을 만들거나 외래키(Foreign Key)를 만들기 위해서 관계를 설정해야한다.
그런데 1:N, N:M 관계 설정이 생각보다 많이 햇갈렸다.
나는 한 필드에서 한 필드로 참조하는 방향에 따라 여러 번 쓰일 수 있는지에 대한 여부에 따라 관계를 구별하였다.
예를 들면 다음과 같다.
1 : N = 유저 : 휴대폰 번호
(유저 → 휴대폰 번호) 특정 유저는 여러 개의 휴대폰 번호를 가질수 있다.
(휴대폰 번호 → 유저) 특정 휴대폰 번호는 오직 특정 유저에게만 귀속된다.
결론: 유저는 한 명이고, 휴대폰 번호는 여러 개가 올 수 있음.
N : M = 유저 : 여행상품
(유저 → 여행상품) 특정 유저는 여러 개의 여행상품을 구매할 수 있다.
(여행상품 → 유저) 특정 여행상품은 여러 유저에 귀속될 수 있다.
나의 프로젝트는 다음과 같은 관계를 갖는다.
teacher : class = 1 : N
(선생님 → 클래스) 특정 선생님은 여러 클래스를 오픈 할 수 있다.
(클래스 → 선생님) 특정 클래스는 한 선생님에 의해서 오픈된다.
region : class = 1 : N
(지역 → 클래스) 특정 지역은 여러 클래스에 들어갈 수 있다.
(클래스 → 지역) 특정 클래스는 한 지역만 갖는다.
class : class_course = 1 : N
(클래스 → 클래스 코스) 특정 클래스는 여러 코스를 가질 수 있다.
(클래스코스 → 클래스) 특정 코스는 한 클래스에만 귀속된다.
user : class_review = 1 : N
(유저 → 클래스 리뷰) 특정 유저는 여러 리뷰를 작성할 수 있다.
(클래스 리뷰 → 유저) 특정 클래스 리뷰는 특정 유저에 귀속된다.
teacher : class = 1 : N
(강사 → 클래스) 특정 강사는 여러 클래스를 개설할 수 있다.
(클래스 → 강사) 특정 클래스는 한 강사에 의해서만 개설될 수 있다.
user : class = N : M
다대다 관계로 인해 생성된 조인 테이블 :
- 유저가 찜한 클래스
(유저 → 클래스) 특정 유저는 여러 클래스를 찜 할 수 있다.
(클래스 → 유저) 특정 클래스는 여러 유저에 의해 찜 당할 수 있다.
- 유저가 구매한 클래스
(유저 → 클래스) 특정 유저는 여러 클래스를 구매할 수 있다.
(클래스 → 유저) 특정 클래스는 여러 유저에 의해 구매될 수 있다.
3. 생성 테이블 및 컬럼
- 사용자 : 로그인 아이디, 패스워드, 닉네임, 이름, 생년월일, 성별, 프로필이미지url, 관리자 여부
- 클래스 : 클래스명, 강사 아이디, 가격, 온/오프라인, 지역 아이디, 평점, 할인율, 생성일자, 배너이미지 url, 콘텐츠(클래스 소개)
- 동영상 : 클래스아이디, 커리큘럼아이디, 강의 순서 ==> 커리큘럼과 1:1관계이므로 따로 테이블을 생성하지 않기로 한다
- 커리큘럼 : 커리큘럼명, 클래스아이디, 커리큘럼아이디, 강의 순서, 동영상url
- 관심 클래스: 유저 아이디, 클래스 아이디
- 구매한 클래스 : 유저 아이디, 클래스 아이디
- 개설한 클래스 : 선생님 아이디, 클래스 아이디, 개설일
- 리뷰 : 유저 아이디, 클래스 아이디, contents, 평점, 작성일
- 리뷰 이미지 : 리뷰 아이디, 클래스 아이디, 이미지url, 생성일
- QnA : 클래스 아이디, q contents, q 아이디, q 작성일, a contents, a 아이디, a 작성일
- 지역: 지역명
🙌 해결책
- 클래스 > 클래스 콘텐츠 > 클래스 소개는 Ckeditor를 사용하여 강사가 작성하는 글과 이미지가 순서대로 통째로 저장될 수 있도록 할 것이다.?
(ckeditor 사용법을 잘 몰라서 추후 변동 사항이 있을 것으로 예상이 됨)
- 강사 테이블을 따로 만들지 않고, 일반 사용자 테이블에 강사인지 아닌지 구별하는 필드 생성할 예정
- 동영상 업로드 순서: 강의 개설 신청 -> 관리자로부터 승인 -> 동영상 업로드 버튼이 활성화
- 이미지 테이블은 리뷰 이미지만 따로 만들고, 생성일 필드를 만들어 등록된 순서대로 게시될 수 있도록 함
- 질의 응답은 질문과 응답을 따로 분리하지 않고 하나의 테이블로 만듦.
완성된 DB 모델링 이미지
많은 도움이 되었습니다. 감사합니다~