DB part.6

2025. 6. 12. 10:00·Daily Logs/TIL (Today I Learned)
데이터베이스 정규화: 1NF, 2NF, 3NF 완벽 정리!

데이터베이스 정규화: 1NF, 2NF, 3NF 완벽 정리!

1NF (제 1 정규형) → 데이터를 "정돈"하기

1NF를 간단하게 말하면 테이블의 각 레코드가 원자값(atomic value)을 가져야 한다는 규칙이에요. 즉, 한 셀에 여러 개의 값이 들어가면 안 된다는 뜻입니다. 이건 테이블을 깔끔하게 만들기 위한 첫 단계로 데이터가 "정돈된" 상태여야 하는 것을 의미하죠.

1NF는 기본적으로 두 가지를 요구해요.

  • 모든 값이 원자적이어야 한다! 하나의 레코드에 여러 개의 값이 들어가지 않도록 해야 해요. 즉, 하나의 레코드에 여러 명의 플레이어, 여러 개의 아이템을 넣지 않고 하나의 값만 넣어야 합니다.
  • 모든 Row가 고유해야 한다! 각 Row가 고유해야 하며 중복된 Row가 없어야 합니다. 동일한 데이터를 여러 번 기록하지 않도록 해야 해요.

요구사항을 보면 알 것 같기도 하나 그래도 예시로 보는게 좀 더 확실하겠죠? MMORPG 게임으로 예시를 들어보자면 MMORPG에서는 플레이어와 그들의 아이템을 관리하는 테이블이 있을 수 있어요. 한 명의 플레이어가 여러 개의 아이템을 착용할 수 있죠. 이제 1NF 규칙에 맞게 데이터를 정돈하지 않았을 때부터 한 번 보시죠.

[Before 1NF]

player_id player_name equipped_items
1 호호아줌마 검, 방패, 투구
2 르탄이 활, 화살, 신발
3 한방에주님곁으로 지팡이

여기서 문제가 보이시나요? equipped_items 칸에 여러 개의 아이템이 쉼표로 구분되어 들어가 있다는 겁니다. 이건 1NF의 규칙을 위반한 상태인데요. 왜냐하면, 한 칸에 여러 개의 값이 들어갔기 때문이죠.

그러면, 이제 이 테이블을 1NF 규칙에 맞게 정돈해볼게요. 한 셀에는 하나의 값만 들어가도록 수정하면 다음과 같이 바꿀 수 있습니다.

[After 1NF]

player_id player_name equipped_item item_type
1 호호아줌마 검 무기
1 호호아줌마 방패 방어구
1 호호아줌마 투구 방어구
2 르탄이 활 무기
2 르탄이 화살 무기
2 르탄이 신발 기타
3 한방에주님곁으로 지팡이 무기

좋아요! 각 셀에는 하나의 값만 들어가도록 변경되었어요. 모든 레코드가 원자적임을 보장하는 것이 1NF에요!

Q. 만약, 이렇게 하지 않고 이전 테이블을 쓴다면 어떠한 불편함이 있을까요? (5분동안 생각해보기)

어떤 불편함이 있냐면요…
- 한 플레이어의 아이템 중 특정 아이템을 검색해야 할 때, 쉼표로 구분된 여러 값을 일일이 찾아야 해서 복잡해집니다.
- 한 아이템을 수정하거나 삭제할 때, 쉼표로 구분된 데이터 안에서 특정 값만 수정해야 해서 실수가 발생할 가능성이 커집니다.
즉, 1NF로 정리된 테이블은 데이터 검색, 수정이 훨씬 더 효율적이고 안정적입니다.

그런데, 이게 완벽해보여도 조금 아쉬운 부분이 있어요. 아래처럼 테이블을 잘라놓고 보면 '호호아줌마'의 정보가 3번 반복됩니다. 호호아줌마라는 플레이어가 각 아이템을 착용하고 있기 때문에, 각 아이템마다 플레이어 정보가 중복된 것이죠.

player_id player_name equipped_item item_type
1 호호아줌마 검 무기
1 호호아줌마 방패 방어구
1 호호아줌마 투구 방어구

뭐, 3개쯤이야… 할 수 있겠지만 플레이어의 슬롯이 많아져서 아이템 착용이 많아진다면? 쓸데없이 데이터가 계속 낭비될 수도 있을거에요. 이렇게 1NF를 사용해서 데이터의 기본적인 정리와 관리를 잘 해냈지만 데이터 중복이라는 이슈가 있네요? 이 이슈를 해결하기 위해 2NF를 도입할 수 있습니다!

2NF (제 2 정규형) → “부분 종속성” 제거로 중복 데이터 줄이기!

이 테이블을 보면 item_type(아이템 유형)은 equipped_item에만 종속되어 있으며 player_id와는 관계가 없다는 것을 알 수 있습니다. 사실 이 테이블에선 player_id + equipped_item이 복합 기본키인데요. 복합 기본키란 두 개 이상의 컬럼을 조합하여 하나의 기본키로 사용하는 것을 말합니다.

이렇게, 복합 기본키의 일부에만 종속되는 비주요 속성이 있는 경우에 부분 종속성이 있다고 합니다. 예를 들어, '검'이 '무기'라는 정보는 player_id와는 무관하고 '검'이라는 아이템 자체에만 의존하죠.

이렇게 부분 종속성이 있으면 데이터가 중복되기 시작하고, 데이터 갱신 이상 문제를 야기할 수 있어요. 예를 들어, “방어구”라는 아이템 타입이 “방어아이템”과 같은 이름으로 일괄적으로 바뀐다고 가정해볼게요. 그런데, 실수로 호호아줌마의 투구의 item_type을 "방어아이템"으로 바꾸지 못한 것입니다. 그러면 다음과 같이 데이터 불일치가 발생할 수 있습니다.

[Before]

player_id player_name equipped_item item_type
1 호호아줌마 검 무기
1 호호아줌마 방패 방어아이템
1 호호아줌마 투구 방어구

이렇게 되면 데이터의 일관성이 깨지게 되죠. 이를 해결하려면 부분 종속성을 제거하고 각 속성이 완전히 기본 키 전체에 종속되도록 테이블을 분리해야 합니다.

[After 2NF]

플레이어 착용 아이템 테이블

player_id player_name equipped_item
1 호호아줌마 검
1 호호아줌마 방패
1 호호아줌마 투구

아이템 정보 테이블

equipped_item item_type
검 무기
방패 방어구
투구 방어구

아이템 정보 테이블을 분리함으로써, item_type을 수정하고 싶다면 아이템 테이블에서 한 번만 수정하면 되기 때문에 수정할 때 실수할 일이 줄어듭니다. 예를 들어, 검이 “무기”가 아니라 “새로운 유형”으로 바뀌면, 한 번의 수정으로 전체 시스템에 반영할 수 있습니다! 이렇게 2NF를 사용하면 데이터베이스의 크기도 줄어들고 수정 및 관리 작업이 간단해져요!

3NF (제 3 정규형) → “이행 종속성” 제거로 중복 데이터 최고로 줄이기!

이제, 우리가 길드에 가입을 했다고 가정을 해보겠습니다. 유저가 가입한 길드 정보가 있는 테이블이 다음과 같이 있다고 가정할게요.

[Before 3NF]

player_id guild_name guild_master
1 전승 코리
2 일심 우엉이
3 번개 마리
4 일심 우엉이

해당 테이블에서 player_id는 기본 키에요. 근데, 여기선 좀 특이한게 길드 이름을 통해 그 길드의 길드장까지 알 수가 있는데요. 이것을 바로 이행 종속성이라고 합니다. 이행 종속성은 기본 키에 직접적으로 종속되지 않고, 다른 속성을 통해 간접적으로 종속되는 속성이 있을 때 발생합니다.

이행 종속성을 기호로 표현하자면 A → B, B → C의 관계가 성립할 때, A → C가 성립하는 것이에요. 해당 테이블에서도 마찬가지인데요. player_id → guild_name이고 guild_name → guild_master라서 결국 player_id → guild_master에요.

  • player_id를 통해 그 플레이어가 속한 길드 이름을 알 수 있고요.
  • 길드 이름을 통해 그 길드의 길드장을 알 수 있어요.
  • 결론적으로 player_id를 알면 길드장까지 알 수 있게 되는 것입니다.

그런데, 길드장의 정보가 바뀌면 어떻게 될까요? '일심'이라는 길드에서 “우엉이” 대신 “연근이”가 길드장이 되면 '일심' 길드에 속한 모든 플레이어의 길드장 정보를 수정해야 합니다. 매우 비효율적이죠. 따라서, 길드 정보 테이블을 따로 만들어서 이행 종속성을 제거하고 비주요 속성이 기본키에만 직접적으로 의존할 수 있도록 해야합니다!

[After 3NF]

플레이어-길드 테이블

player_id guild_id
1 1
2 2
3 3
4 2

길드 정보 테이블

guild_id guild_name guild_master
1 전승 코리
2 일심 우엉이
3 번개 마리

이렇게 말이죠! 길드 이름 대신 guild_id를 사용하는 이유는 길드 이름이 바뀌더라도 ID는 변하지 않으므로 테이블의 일관성을 유지할 수 있기 때문입니다! 바뀐 구조에서 종속성은 이렇게 표현할 수 있겠어요.

  • player_id → guild_id
  • guild_id → (guild_name, guild_master)

이행 종속성이 깔끔하게 제거되었습니다. 이렇게 고치고 나니 길드장 정보가 중복되어서 저장되지도 않고 길드장 정보가 항상 일관적으로 유지됩니다! 이제 데이터베이스 정규화에 대해서 감이 좀 잡히시나요?

직접, 정규화 실습을 해볼까요?!

Q. 아래의 도서관 대출 기록 테이블을 2NF로 정규화를 해보세요!
loan_id member_id member_name member_addr book_id book_title author_name loan_date return_date
101 1 호호아줌마 서울 201 위대한개츠비 F.스콧 2024-01-01 2024-01-10
102 2 르탄이 인천 202 1984 무라카미하루키 2024-01-05 2024-01-12
103 1 호호아줌마 서울 203 그리스로마신화 홍은영 2024-01-08 2024-01-18
104 3 연근이 수원 204 총균쇠 제러드 2024-01-10 2024-01-20

[정답]

대출 기록 테이블

loan_id member_id book_id loan_date return_date
101 1 201 2024-01-01 2024-01-10
102 2 202 2024-01-05 2024-01-12
103 1 203 2024-01-08 2024-01-18
104 3 204 2024-01-10 2024-01-20

회원 정보 테이블

member_id member_name member_addr
1 호호아줌마 서울
2 르탄이 인천
3 연근이 수원

도서 정보 테이블

book_id book_title author_name
201 위대한개츠비 F.스콧
202 1984 무라카미하루키
203 그리스로마신화 홍은영
204 총균쇠 제러드

✨ 혹시 몰라서 요약본까지! ✨

1NF (제 1 정규형)

  • 목적: 데이터를 원자적 값으로 분해
  • 핵심 규칙: 각 컬럼은 원자적 값만 포함 + 반복되는 그룹이 없어야 함
  • 결과: 데이터의 기본적인 구조화 달성

2NF (제 2 정규형)

  • 목적: 부분 종속성 제거
  • 핵심 규칙: 비주요 속성이 기본키 전체에 완전 함수적 종속
  • 결과: 데이터 중복 감소 및 갱신 이상 문제 해결

3NF (제 3 정규형)

  • 목적: 이행 종속성 제거
  • 핵심 규칙: 비주요 속성 간의 종속성 제거
  • 결과: 데이터의 일관성 유지 및 갱신 용이성 증가

정규화의 일반적인 이점

  • 데이터 중복 최소화
  • 데이터 일관성 향상
  • 데이터 갱신 이상 방지
  • 구조화된 데이터베이스 설계 가능

🚨 정규화 시 주의사항: 과도한 정규화는 성능 저하를 야기할 수 있으므로 상황에 맞는 적절한 수준의 정규화가 필요합니다!

'Daily Logs > TIL (Today I Learned)' 카테고리의 다른 글

데이터베이스 인덱스  (1) 2025.06.14
DB part.7  (2) 2025.06.13
DB part.5  (2) 2025.06.11
DB part.4  (1) 2025.06.10
DB part.3  (0) 2025.06.09
'Daily Logs/TIL (Today I Learned)' 카테고리의 다른 글
  • 데이터베이스 인덱스
  • DB part.7
  • DB part.5
  • DB part.4
Jcob.moon
Jcob.moon
반가워요~ 하루하루 꾸준히 코딩 작성하는 곳입니다 !!
  • Jcob.moon
    Pixelated Thoughts
    Jcob.moon
  • 전체
    오늘
    어제
    • HelloWorld (174) N
      • Daily Logs (123) N
        • TIL (Today I Learned) (64) N
        • Algorithm Practice (55)
        • Dev Book Notes (4)
      • Deep Dives (36)
        • 문제 해결 (Troubleshooting) (3)
        • CS Fundamentals (22)
        • Career Prep (4)
        • Technical Notes (7)
      • Project Log (7)
      • Any (3)
      • Cooperation (4)
        • Github (2)
        • Conventions (1)
        • Git (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
Jcob.moon
DB part.6
상단으로

티스토리툴바