[DB 설계] 데이터베이스 모델링(Database Modeling) - 제 1 정규형(1NF, First Normal Form)

iiingkeep·2024년 11월 4일

Database

목록 보기
15/21

제 1 정규형(1NF, First Normal Form)

규칙: 하나의 속성은 한 개의 속성값만 가질 수 있다.

아래와 같이 users Table이 있을 때, 이메일 속성의 속성값이 여러개인 것을 볼 수 있다.

users Table

id이름이메일
1김지민k@mail.com, kjm@nmail.com
2이은서e@mail.com, eee@nmail.com

그렇다면 이런 테이블은 어떤 문제가 있을까?

  • 데이터를 꺼내 쓸 때 split을 사용해야하는 번거로움
  • 중복의 위험성

해결 방법

테이블을 분리한다.

기존의 테이블에서 여러값이 들어갔던 컬럼 이메일을 기존 테이블에서 삭제한 뒤 아래와 같이 이메일 테이블을 따로 생성한다.

users Table

id이름
1김지민
2이은서

emails Table

id이메일
1k@mail.com
2kjm@nmail.com
3e@mail.com
4eee@nmail.com

위와 같이 테이블을 분리하면 속성값이 한 개여야 한다는 규칙은 지켜졌지만 각 이메일이 어떤 유저의 이메일인지 알 수 없게 되었다. 각 이메일이 어떤 유저의 이메일인지 표시해주기 위해 취할 수 있는 방법은 두 가지가 있다.

첫 번째 방법

emails 테이블의 이메일 id를 users 테이블의 FK로 가져와 사용

users Table

id이름이메일 id(FK)
1김지민1, 2
2이은서3, 4

emails Table

id이메일
1k@mail.com
2kjm@nmail.com
3e@mail.com
4eee@nmail.com

두 번째 방법

users 테이블의 유저 id를 emails 테이블의 FK로 가져와 사용

users Table

id이름
1김지민
2이은서

emails Table

id이메일유저 id(FK)
1k@mail.com1
2kjm@nmail.com1
3e@mail.com2
4eee@nmail.com2

첫 번째 방법은 다시 속성값이 두 개가 되어 규칙이 지켜지지 않는 반면
두 번째 방법은 모두 한 개의 속성값을 가지며 어떤 유저가 어떤 이메일을 사용하는지도 알 수 있다.
그러므로 두 번째 방법을 통해 테이블을 분리하는 것이 좋다.

이렇게 속성값을 여러 개 가지던 테이블을 분리해 속성값을 하나만 가지도록 하는 과정을 정규화의 과정 중 제 1 정규화라고 하며, 제 1 정규화를 통해 각 속성은 속성값을 하나만 가져야한다는 규칙에 부합하게 만든 테이블을 제 1정규형(1NF, First Normal Form)이라고 한다.
두 번째 방법을 통해 정규화한 users 테이블과 emails 테이블은 제 1정규형을 만족한다고 할 수 있다.

다른 예시를 더 보자.
아래와 같이 판매 상품 속성의 속성값이 여러개인 테이블이 있다.

stores Table

id가게명판매 상품
1DB 카페아메리카노, 카페라떼
2데이터 국밥수육국밥, 순대국밥, 선지국밥


제 1 정규화를 거치면 아래와 같이 제 1 정규형을 만족하는 각각의 테이블로 분리된다.

stores Table

id가게명
1DB 카페
2데이터 국밥

products Table

id판매 상품가게 id(FK)
1아메리카노1
2카페라떼1
3수육국밥2
4순대국밥2
5선지국밥2




위와 같이 테이블을 하나 생성해 FK를 설정함으로써 제 1정규형을 만족시킬 수 있는 상황이 있는 반면 그러지 못하는 상황도 존재한다.
여러개의 속성값이 여러 인스턴스에 중복해서 나타는 경우이다.

아래와 같이 students Table이 있을 때, 수강 과목 속성의 속성값이 여러개인 것을 볼 수 있으며 이는 제 1정규형을 만족하지 못한다. 또한 이 속성값들은 여러 행에 분포되어 있다.

students Table

id이름수강 과목
1김지민국어, 수학
2이은서수학, 과학
3전서진국어, 과학

규칙: 어떤 테이블에 FK를 넣어도 제 1 정규형을 만족하지 않을 때, 중간 테이블을 생성한다.

해결 방법

위의 규칙에 따라 해결한다.
먼저, 위에서 했던 것 처럼 제 1 정규화를 통해 테이블을 분리 해 본다.

첫 번째 방법

과목 테이블을 따로 생성한 뒤 학생 테이블에 과목 id를 FK로 가져온다.

students Table

id이름과목 id(FK)
1김지민1, 2
2이은서2, 3
3전서진1, 3

subjects Table

id과목명
1국어
2수학
3과학

두 번째 방법

과목 테이블을 따로 생성한 뒤 과목 테이블에 학생 id를 FK로 가져온다.

users Table

id이름
1김지민
2이은서
3전서진

emails Table

id과목명학생 id(FK)
1국어1, 3
2수학1, 2
3과학2, 3

이전에 했던 정규화 방식을 통해 테이블을 분리하고 FK를 설정해봤지만 두 방법 모두 속성값이 원자값이 되지 못해 제 1 정규형을 만족하지 못한다.


세 번째 방법

중간 역할을 하는 테이블을 하나 더 생성한 뒤 FK를 설정한다.

students Table

id이름
1김지민
2이은서
3전서진

subjects Table

id과목명
1국어
2수학
3과학

course_registrations Table

id학생 id(FK)과목 id(FK)
111
212
322
423
531
633

students table과 subjects table에 더해 둘의 '관계'가 되는 '수강' 테이블, 즉 course_registrations table을 생성해주고 속성으로 학생 테이블의 id와 과목 테이블의 id를 FK로 받아왔다.
이렇게 하나의 테이블을 더 생성해주면 제 1 정규형을 만족하면서 어떤 학생이 어떤 과목을 수강하는지도 조회가 가능하다.


다른 예시를 더 보자.
아래와 같이 배우명의 속성값이 여러개인 테이블이 있을 때 제 1 정규형을 만족하도록 제 1 정규화를 진행한다.

movies Table

id이름배우명
1서울의 봄정우성, 황정민
2크로스염정아, 황정민
3밀수김혜수, 염정아


첫 번째 방법

배우 관련 데이터로 구성된 actors table을 생성한 뒤 movies table에 배우명 id를 FK로 가져온다.

movies Table

id이름배우명 id(FK)
1서울의 봄1, 2
2크로스2, 3
3밀수3, 4

actors Table

id이름
1정우성
2황정민
3염정아
4김혜수

두 번째 방법

배우 관련 데이터로 구성된 actors table을 생성한 뒤 actors table에 영화명 id를 FK로 가져온다.

movies Table

id이름
1서울의 봄
2크로스
3밀수

actors Table

id이름영화명 id(FK)
1정우성1
2황정민1, 2
3염정아2, 3
4김혜수3

세 번째 방법

영화와 배우를 이어주는 중간 테이블인 캐스트 테이블, 즉 casts table을 생성한 뒤 영화명 id와 배우명 id를 FK로 가져온다.

movies Table

id이름
1서울의 봄
2크로스
3밀수

actors Table

id이름
1정우성
2황정민
3염정아
4김혜수

casts Table

id영화명 id(FK)배우명 id(FK)
111
212
322
423
533
634

첫 번째 방법과 두 번째 방법으로 정규화를 진행한 경우 여전히 제 1 정규형을 만족하지 못한다.
반면 세 번째 방법으로 영화와 배우의 중간 역할이 되는 캐스트 테이블을 추가 생성하여 정규화를 진행한 경우 제 1 정규형을 만족하면서 어떤 영화에 어떤 배우가 출연하는지의 여부까지 알 수 있게 된다.


참고

이 게시글은 박재성님의 비전공자도 이해할 수 있는 DB 설계 입문/실전 강의를 토대로 작성되었습니다.
https://www.inflearn.com/course/%EB%B9%84%EC%A0%84%EA%B3%B5%EC%9E%90-db-%EC%84%A4%EA%B3%84-%EC%9E%85%EB%AC%B8/dashboard

profile
혁신적인 백엔드 개발자가 되고자, 기록✏️

0개의 댓글