본문 바로가기
강의 정리/비전공자도 이해할 수 있는 DB 설계 입문_실전

DB 설계 규칙

by Backchus 2024. 12. 28.

DB 설계 규칙 6가지

1. 한 칸에는 한 가지 정보만 들어가도록 만들어라.

데이터베이스 테이블을 설계할 때 ‘한 칸에는 한 가지 정보만 들어가야 한다.’라는 규칙을 지켜야 한다. 이 규칙이 뭔지 알아보기 위해 이 규칙을 안 지킨 사례를 먼저 살펴보자.

[사례 1]

students (학생)

id (PK) 이름 연락처
1 김철수 010-1234-5678, 010-8765-4321
2 이영희 010-1111-2222, 010-3333-4444

위 사례를 살펴보면 한 칸에 2가지 이상의 정보가 들어가 있는 걸 확인할 수 있다.

“왜 한 칸에 2가지 이상의 정보가 들어가면 안 되는 걸까?”

데이터를 삽입하거나 수정할 때 로직이 복잡해지고, 데이터 중복 및 무결성 문제가 발생할 가능성이 높아진다. 따라서 한 칸에는 한 가지 정보만 넣어야 한다.


한 칸에 2개 이상의 정보가 들어가 있을 땐?

한 칸에 2가지 이상의 정보가 들어가 있을 때는 테이블을 분리해야 한다. 테이블을 분리함으로써 한 칸에 한 가지 정보만 들어가도록 해야 한다.

[사례 1 - 테이블 분리]

students (학생)

id (PK) 이름
1 김철수
2 이영희

contacts (연락처)

id (PK) 연락처 학생 id (FK)
1 010-1234-5678 1
2 010-8765-4321 1
3 010-1111-2222 2
4 010-3333-4444 2

위와 같이 테이블을 분리함으로써 한 칸에 한 가지 정보만 들어가게 만들었다.


✅ 또 다른 사례

[사례 2]

orders (주문)

id (PK) 주문자 이름 주문 상품
1 박지훈 노트북, 무선 마우스
2 김나연 스마트폰, 충전기, 이어폰

[사례 2 - 테이블 분리]

orders (주문)

id (PK) 주문자 이름
1 박지훈
2 김나연

products (상품)

id (PK) 상품명 주문 id (FK)
1 노트북 1
2 무선 마우스 1
3 스마트폰 2
4 충전기 2
5 이어폰 2

이 과정을 데이터베이스 이론에서는 제1정규형(1NF)이라고 부른다. 학문적인 용어를 외우는 것보다, 테이블을 설계하고 데이터를 효율적으로 관리하는 능력을 기르는 것이 더 중요하다.

'한 가지 정보'라는게 관점에 따라 달라질 수 있다.

‘한 가지 정보’라는 기준은 절대적이지 않다. 데이터의 활용 목적이나 서비스의 요구사항에 따라 ‘한 가지 정보’로 볼 수 있는 관점이 달라질 수 있다.

[예시 1: 주소 정보]

address (주소)

id (PK) 주소
1 서울특별시 강남구 테헤란로 12
2 부산광역시 해운대구 우동 123
  • 문제점: 시/도, 구/군, 상세주소가 하나의 칸에 통합되어 있다.
  • 해결: 분리된 형태로 저장하여 검색 및 수정 편의성을 높인다.

[분리 후]

addresses (주소)

id (PK) 시/도 구/군 상세주소
1 서울특별시 강남구 테헤란로 12
2 부산광역시 해운대구 우동 123

[예시 2: 복합 키워드]

products (상품)

id (PK) 상품명 키워드
1 노트북 전자제품, 휴대용, 고성능
2 의자 가구, 인테리어, 편안함
  • 문제점: 키워드가 한 칸에 여러 값으로 들어가 있어 필터링이나 검색이 어려움.
  • 해결: 키워드를 별도 테이블로 분리하여 다대다 관계로 저장한다.

[분리 후]

products (상품)

id (PK) 상품명
1 노트북
2 의자

product_keywords (상품 키워드)

id (PK) 상품 id (FK) 키워드
1 1 전자제품
2 1 휴대용
3 1 고성능
4 2 가구
5 2 인테리어
6 2 편안함

[예시 3: 다국어 지원]

menus (메뉴)

id (PK) 메뉴명
1 커피 (Coffee)
2 차 (Tea)
  • 문제점: 다국어 데이터가 한 칸에 혼합되어 있다.
  • 해결: 언어별로 메뉴명을 분리하여 저장한다.

[분리 후]

menus (메뉴)

id (PK) 언어 메뉴명
1 ko 커피
2 en Coffee
3 ko
4 en Tea

요약

  • 한 칸에는 한 가지 정보만 들어가야 한다.
  • 한 칸에 두 가지 이상의 정보가 들어가있을 땐, 테이블을 분리해서 FK를 활용하면 된다.
  • 특정 테이블에 FK를 도입했을 때 규칙1이 안 지켜진다면, 다른 테이블로 FK를 옮겨본다.
  • '한 가지 정보'의 기준은 절대적이지 않다. 따라서 서비스에 맞게 판단해야 한다.

DB 설계 규칙 6가지

2. 어떤 테이블에 FK를 넣어도 '규칙 1'을 못 지킬 때는 중간 매핑테이블을 하나 더 만들어라.

FK(외래 키)를 활용할 때도 한 칸에 한 가지 정보만 넣는 규칙(규칙 1)을 지키는 것이 중요하다. 하지만 어떤 상황에서는 특정 테이블에 FK를 넣어도 여전히 한 칸에 여러 정보가 들어가게 된다. 이 경우에는 중간 매핑 테이블을 추가하여 해결할 수 있다.


예시: 학생과 수강 과목

학생이 여러 과목을 수강할 수 있고, 한 과목에 여러 학생이 등록할 수 있는 다대다(M:N) 관계를 설계한다고 가정하자.

[잘못된 설계]

students (학생)

id (PK) 이름 수강 과목 id (FK)
1 김철수 1, 2
2 이영희 2, 3

subjects (과목)

id (PK) 과목명
1 수학
2 과학
3 영어
  • 문제점: students 테이블의 수강 과목 id 컬럼에 여러 값이 들어가 있어 규칙 1이 위배된다.
  • 해결 방법: 중간 매핑 테이블을 생성하여 학생과 과목의 관계를 별도로 관리한다.

[중간 매핑 테이블을 사용한 설계]

students (학생)

id (PK) 이름
1 김철수
2 이영희

subjects (과목)

id (PK) 과목명
1 수학
2 과학
3 영어

student_subjects (학생-과목 매핑)

id (PK) 학생 id (FK) 과목 id (FK)
1 1 1
2 1 2
3 2 2
4 2 3
  • 설명: student_subjects라는 중간 매핑 테이블을 생성하여 학생과 과목 간의 관계를 관리한다.
  • 장점:
    • 규칙 1을 지키며 다대다 관계를 효과적으로 표현할 수 있다.
    • 추가적인 속성(예: 수강 신청 날짜, 점수 등)을 중간 매핑 테이블에 쉽게 추가할 수 있다.

예시: 주문과 제품

한 주문에 여러 제품이 포함될 수 있고, 한 제품이 여러 주문에 포함될 수 있는 다대다(M:N) 관계를 설계한다고 가정하자.

[잘못된 설계]

orders (주문)

id (PK) 주문자 제품 id (FK)
1 박지훈 1, 2
2 김나연 2, 3

products (제품)

id (PK) 제품명
1 노트북
2 스마트폰
3 충전기
  • 문제점: orders 테이블의 제품 id 컬럼에 여러 값이 들어가 있어 규칙 1이 위배된다.
  • 해결 방법: 중간 매핑 테이블을 생성하여 주문과 제품의 관계를 별도로 관리한다.

[중간 매핑 테이블을 사용한 설계]

orders (주문)

id (PK) 주문자
1 박지훈
2 김나연

products (제품)

id (PK) 제품명
1 노트북
2 스마트폰
3 충전기

order_products (주문-제품 매핑)

id (PK) 주문 id (FK) 제품 id (FK)
1 1 1
2 1 2
3 2 2
4 2 3
  • 설명: order_products라는 중간 매핑 테이블을 생성하여 주문과 제품 간의 관계를 관리한다.
  • 장점:
    • 다대다 관계를 효과적으로 분리하고, 규칙 1을 지킨다.
    • 주문별 제품 수량, 할인율 등 추가 정보를 매핑 테이블에 쉽게 저장할 수 있다.

중간 매핑 테이블을 사용하는 것은 다대다 관계를 표현할 때뿐만 아니라, 복잡한 데이터 관계를 단순화하고 데이터 무결성을 유지하는 데 매우 유용하다.

DB 설계 규칙 6가지

3. 헷갈릴 땐 관계(1:1, 1:N, N:M)를 파악해봐라

데이터를 설계할 때 가장 중요한 것은 테이블 간의 관계를 파악하는 것이다. 관계를 명확히 파악하면 테이블을 어떻게 설계해야 할지 쉽게 결정할 수 있다. 관계는 크게 1:1 관계, 1:N 관계, N:M 관계로 나눌 수 있다.


1:1 관계

1:1 관계는 한 엔티티가 다른 엔티티와 정확히 하나의 데이터와 연결될 때 발생한다.

[예시: 사용자와 사용자 프로필]

  • 사용자 정보는 users 테이블에, 프로필 정보는 profiles 테이블에 저장된다.
  • 각 사용자는 하나의 프로필만 가질 수 있다.

[테이블 설계]

users (사용자)

id (PK) 이름
1 김철수
2 이영희

profiles (프로필)

id (PK) 사용자 id (FK) 프로필 이미지 자기소개
1 1 profile1.jpg 안녕하세요, 김철수입니다.
2 2 profile2.jpg 안녕하세요, 이영희입니다.
  • 설명: profiles 테이블의 사용자 idusers 테이블의 id와 1:1로 매칭된다.
  • 활용: 테이블 분리를 통해 데이터 접근 속도를 높이고, 각 테이블의 역할을 명확히 할 수 있다.

1:N 관계

1:N 관계는 하나의 엔티티가 여러 개의 다른 엔티티와 연결될 때 발생한다.

[예시: 카테고리와 제품]

  • 하나의 카테고리는 여러 제품을 포함할 수 있다.
  • 각 제품은 하나의 카테고리에만 속한다.

[테이블 설계]

categories (카테고리)

id (PK) 카테고리명
1 전자제품
2 가구

products (제품)

id (PK) 제품명 카테고리 id (FK)
1 노트북 1
2 스마트폰 1
3 의자 2
4 테이블 2
  • 설명: products 테이블의 카테고리 idcategories 테이블의 id를 참조하여 여러 제품이 하나의 카테고리에 연결된다.
  • 활용: 각 카테고리별로 제품을 쉽게 조회할 수 있다.

N:M 관계

N:M 관계는 여러 엔티티가 여러 엔티티와 연결될 때 발생한다. 이를 표현하기 위해 중간 매핑 테이블이 필요하다.

[예시: 학생과 과목]

  • 학생은 여러 과목을 수강할 수 있고, 한 과목에는 여러 학생이 등록될 수 있다.

[테이블 설계]

students (학생)

id (PK) 이름
1 김철수
2 이영희

subjects (과목)

id (PK) 과목명
1 수학
2 과학
3 영어

student_subjects (학생-과목 매핑)

id (PK) 학생 id (FK) 과목 id (FK)
1 1 1
2 1 2
3 2 2
4 2 3
  • 설명: student_subjects 테이블은 학생과 과목 간의 N:M 관계를 중간 매핑 테이블로 관리한다.
  • 활용: N:M 관계를 유연하게 처리하고 추가 정보를 저장할 수 있다.

엔티티 관계 파악 방법

1. 엔티티 간에 어울리는 동사 찾기

관계를 파악할 때는 두 엔티티 간의 의미를 동사로 표현해보면 명확해진다.

  • A(주어)가 B를 _____. (A가 주어)

    • 예: 학생이 과목을 수강한다.
    • 결과: 학생-과목은 N:M 관계.
  • B(주어)가 A에 의해 _____. (B가 주어)

    • 예: 과목이 학생에 의해 수강된다.
    • 결과: 과목-학생은 N:M 관계.

2. 관계를 기준으로 테이블 분리 여부 결정

  • 1:1 관계: 엔티티를 분리하고 FK로 연결.
  • 1:N 관계: N 테이블에 FK 추가.
  • N:M 관계: 중간 매핑 테이블을 생성.

DB 설계 규칙 6가지

4. 데이터 중복이 발생하는 컬럼이 있는지 확인해라

데이터베이스 설계 시 데이터 중복이 발생하면 저장 공간 낭비, 데이터 무결성 문제, 유지보수 비용 증가 등의 문제가 발생할 수 있다. 따라서, 데이터 중복 가능성을 미리 시뮬레이션하여 중복이 발생하는 컬럼을 찾아야 한다.


데이터 중복이란?

  • 동일한 데이터가 여러 행에 반복적으로 저장되는 경우를 의미한다.
  • 예를 들어, 고객의 도시 정보가 여러 고객 레코드에서 반복된다면 이는 데이터 중복의 한 예이다.

데이터 중복 사례

[예시: 고객과 도시 정보]

[잘못된 설계]

customers (고객)

id (PK) 이름 도시
1 김철수 서울특별시 강남구
2 이영희 서울특별시 강남구
3 박지훈 부산광역시 해운대구
4 최민수 서울특별시 강남구
  • 문제점:
    • 도시 정보가 여러 행에서 반복적으로 저장된다.
    • 저장 공간 낭비 및 데이터 변경 시 모든 행을 수정해야 하는 비효율 발생.

[해결 방법: 테이블 분리]

  • 도시 정보를 별도의 테이블로 분리하고, FK로 참조하도록 설계한다.

[분리 후 설계]

customers (고객)

id (PK) 이름 도시 id (FK)
1 김철수 1
2 이영희 1
3 박지훈 2
4 최민수 1

cities (도시)

id (PK) 도시 이름
1 서울특별시 강남구
2 부산광역시 해운대구
  • 장점:
    • 도시 정보는 cities 테이블에 한 번만 저장된다.
    • 중복된 도시 정보를 제거하여 저장 공간을 절약하고, 도시 데이터 수정 시 단일 위치에서 처리 가능.

데이터 중복 시뮬레이션

데이터 중복 여부를 확인하려면 기존 데이터를 분석하거나 샘플 데이터를 시뮬레이션하여 중복된 값의 빈도를 확인한다.

시뮬레이션 절차

  1. 테이블에서 특정 컬럼을 기준으로 그룹화하고 중복된 값의 빈도를 확인.
    SELECT 도시, COUNT(*)
    FROM customers
    GROUP BY 도시
    HAVING COUNT(*) > 1;
    

DB 설계 규칙 6가지

5. 가짜 중복과 진짜 중복을 구별해라

데이터베이스 설계 시 데이터를 중복 제거해야 하지만, 중복으로 보이는 데이터가 항상 잘못된 것은 아니다. 따라서, 데이터가 가짜 중복인지, 진짜 중복인지 구별하는 것이 중요하다.

가짜 중복과 진짜 중복의 차이

  • 가짜 중복: 데이터가 반복적으로 나타나지만, 서비스 상에서 별개의 데이터로 취급되어야 한다.
  • 진짜 중복: 동일한 데이터가 반복적으로 저장되어 수정 시 다른 데이터도 영향을 받아야 한다.

가짜 중복인지 진짜 중복인지 판단하려면 이렇게 질문해보면 된다.

“실제 서비스에서 A 데이터의 값을 수정하면, B 데이터의 값도 같이 수정되어야 하는가?”


예시 1: 고객의 주문 내역

[잘못된 설계: 모든 주문에서 고객 이름을 저장]

orders (주문)

id (PK) 고객 이름 주문 상품 주문 날짜
1 김철수 노트북 2024-01-01
2 김철수 마우스 2024-01-02
3 이영희 스마트폰 2024-01-03
  • 문제점: 고객 이름이 여러 주문에서 반복적으로 저장됨.
  • 진짜 중복인지 확인: 만약 김철수의 이름을 "김영수"로 수정한다면, 모든 주문 내역에서도 수정되어야 함.
    • 결과: 진짜 중복 → 고객 정보를 별도 테이블로 분리해야 함.

[분리 후 설계]

customers (고객)

id (PK) 이름
1 김철수
2 이영희

orders (주문)

id (PK) 고객 id (FK) 주문 상품 주문 날짜
1 1 노트북 2024-01-01
2 1 마우스 2024-01-02
3 2 스마트폰 2024-01-03
  • 해결: 고객 이름을 수정하면 모든 주문 내역에서 변경 사항이 반영됨.

예시 2: 제품의 주문 기록

[잘못된 설계: 제품 이름이 중복 저장]

orders (주문)

id (PK) 제품명 수량 주문 날짜
1 노트북 1 2024-01-01
2 노트북 2 2024-01-02
3 스마트폰 1 2024-01-03
  • 문제점: 제품명이 여러 주문에서 반복적으로 저장됨.
  • 진짜 중복인지 확인: 만약 "노트북" 이름을 "울트라 노트북"으로 변경하면 모든 주문 기록에서 변경되어야 함.
    • 결과: 진짜 중복 → 제품 정보를 별도 테이블로 분리해야 함.

[분리 후 설계]

products (제품)

id (PK) 제품명
1 노트북
2 스마트폰

orders (주문)

id (PK) 제품 id (FK) 수량 주문 날짜
1 1 1 2024-01-01
2 1 2 2024-01-02
3 2 1 2024-01-03
  • 해결: 제품 이름을 변경하면 모든 주문 내역에 자동으로 반영됨.

예시 3: 주문 내역에서 할인 쿠폰

[잘못된 설계: 쿠폰 정보 중복 저장]

orders (주문)

id (PK) 주문자 쿠폰 코드 할인 금액
1 김철수 SAVE10 10,000
2 이영희 SAVE10 10,000
3 박지훈 SAVE20 20,000
  • 문제점: 쿠폰 정보가 여러 주문에서 반복적으로 저장됨.
  • 진짜 중복인지 확인: "SAVE10" 쿠폰의 할인 금액이 변경되면 모든 주문 내역에 반영되어야 함.
    • 결과: 진짜 중복 → 쿠폰 정보를 별도 테이블로 분리해야 함.

[분리 후 설계]

coupons (쿠폰)

id (PK) 쿠폰 코드 할인 금액
1 SAVE10 10,000
2 SAVE20 20,000

orders (주문)

id (PK) 주문자 쿠폰 id (FK)
1 김철수 1
2 이영희 1
3 박지훈 2
  • 해결: 쿠폰 할인 금액을 변경하면 모든 주문 내역에서 자동으로 반영됨.

정리

가짜 중복인지 진짜 중복인지 판단 질문

  1. 데이터 A와 B가 동일하다면, 데이터 A를 변경했을 때 B도 변경되어야 하는가?
    • YES: 진짜 중복 → 테이블 분리.
    • NO: 가짜 중복 → 분리 필요 없음.

이 과정을 통해 데이터 중복을 제대로 관리하면 저장 공간을 절약하고, 데이터 무결성을 유지하며, 유지보수 비용을 줄일 수 있다.

DB 설계 규칙 6가지

6. 숨어있는 중복을 찾아라

데이터베이스 설계 시 숨어있는 중복은 명시적으로 드러나지 않지만, 설계의 비효율로 인해 데이터 무결성과 관리에 문제를 야기할 수 있다. 특히, 관련된 데이터를 별도의 테이블로 관리할 경우 숨은 중복이 발생할 가능성이 높다.


예시: 조회수 관리에서의 숨은 중복

[잘못된 설계: 게시물 테이블에서 조회수를 관리]

posts (게시물)

id (PK) 제목 내용 조회수
1 게시물 1 내용 1 100
2 게시물 2 내용 2 50
  • 문제점:
    • 조회수는 동적인 데이터로, 게시물 테이블의 다른 정적인 데이터(제목, 내용)와 성격이 다르다.
    • 조회수 업데이트가 자주 발생하면 게시물 테이블에 불필요한 수정 작업이 자주 일어나 성능에 영향을 미친다.

[해결 방법1: 조회수를 별도의 테이블로 분리]

posts (게시물)

id (PK) 제목 내용
1 게시물 1 내용 1
2 게시물 2 내용 2

post_views (조회수)

id (PK) 게시물 id (FK) 조회수
1 1 100
2 2 50
  • 장점:
    • 조회수 업데이트는 post_views 테이블만 수정하므로, posts 테이블의 성능에 영향을 주지 않음.
    • 조회수와 게시물 데이터를 독립적으로 관리할 수 있음.

[해결 방법: 조회수를 동적으로 계산]

  • 조회수를 별도로 저장하지 않고, 조회 기록 테이블을 기반으로 조회수를 계산하도록 설계.

posts (게시물)

id (PK) 제목 내용
1 게시물 1 내용 1
2 게시물 2 내용 2

post_views (조회 기록)

id (PK) 게시물 id (FK) 사용자 id 조회 일시
1 1 101 2024-01-01 10:00
2 1 102 2024-01-01 10:05
3 2 103 2024-01-01 11:00
  • 조회수 계산 쿼리 예시
    SELECT 게시물.id, 제목, 내용, COUNT(post_views.id) AS 조회수
    FROM posts
    LEFT JOIN post_views ON posts.id = post_views.게시물_id
    GROUP BY posts.id, 제목, 내용;