데이터 베이스/설계 1편, 현대적 데이터 모델링 완전 정복

Ch06. 논리적 모델링(3) - 다대다 관계 모델의 한계

webmaster 2026. 6. 26. 19:56

다대다 관계를 이해하고 올바르게 설계하는 것은 데이터 모델링의 핵심 역량 하나다. 하지만 놀랍게도, 관계형 데이터베이스는 테이블 개만으로 다대다(M:N) 관계를 표현할 없다.

 

관계형 데이터베이스의 기본 제약

진행하기 전에 관계형 데이터베이스의 기본 제약을 다시 확인해보자.

관계형 데이터베이스에서 테이블의 (row) 다음과 같은 특징을 가진다.

  • 기본 키(PK)는 반드시 유일하다.
    • 한 테이블 안에서 동일한 PK를 가진 행은 존재할 수 없다.
  • 외래 키(FK)는 단일 행만 참조한다.
    • 외래 키 값 하나는 상대 테이블의 정확히 한 행만 가리킨다.
  • 컬럼은 원자적(atomic)이어야 한다.
    • 하나의 컬럼에 여러 값을 넣을 수 없다(제1 정규형).

 

테이블로 다대다 관계 시도

다대다 관계

  • 100번 주문이 청바지(1), 티셔츠(2)라는 상품을 둘 다 주문했다.
  • 101번 주문이 청바지(1) 상품을 주문했다.
  • 하나의 주문은 여러 상품을 주문할 있다.
    • 100 주문은 청바지(1), 티셔츠(2) 주문한다.
  • 하나의 상품은 여러 주문에 포함될 있다.
    • 청바지(1) 상품은 100, 101 주문에 포함된다.

 

1. orders 테이블에 외래 키를 두는 방법

 

orders 테이블

orders  테이블에 외래키

  • 이 설계는 제약 2, 제약 3을 위반한다.
    • 외래 키는 단일 행만 참조하는 제약 2를 위반했다.
    • 컬럼은 원자적이어야 하는 제약 3을 위반했다.

제약 2, 제약 3을 만족하려면 다음과 같이 변경해야 한다.

제약 2, 3을 만족하게 수정

 

  • 하지만 이 설계는 제약 1을 위반한다.
  • 기본 키는 반드시 유일해야 하므로 다음과 같이 100번 주문의 행을 더 늘릴 수는 없다.
  • 기본 키는 반드시 유일해야 한다는 제약1을 위반하기 때문에 적용할 수 없다.

따라서 orders 테이블에 외래 키를 없다.

 

2. product 테이블에 외래 키를 두는 방법

 

product 테이블

제약2, 제약3을 위반

  • 청바지는 주문 100, 101 두 번 주문되었다.
  • 설계는 제약 2, 제약 3을 위반한다.
    • 외래 키는 단일 행만 참조하는 제약 2를 위반했다.
    • 컬럼은 원자적이어야 하는 제약 3을 위반했다.

제약 2, 제약 3을 만족하려면 다음과 같이 변경해야 한다.

제약2, 제약3 만족

  • 하지만 이 설계는 제약 1을 위반한다.
  • 기본 키는 반드시 유일해야 하므로 다음과 같이 1번 상품의 행을 더 늘릴 수는 없다.
  • 기본 키는 반드시 유일해야 한다는 제약 1을 위반하기 때문에 적용할 수 없다

따라서 product 테이블에 외래 키를 없다.

 

결과적으로 product, orders 어디에 외래 키를 두더라도 관계형 데이터베이스의 기본 제약을 위반하게 된다. 따라서 다대다 관계를 표현할 없다.

 

관계형 데이터베이스의 한계와 다른 패러다임

관계형 데이터베이스는 테이블 개만으로 다대다(M:N) 관계를 표현할 없다.

이처럼 테이블 개만으로는 양쪽의 '(Many)' 관계를 모두 수용할 없는 것이 관계형 데이터베이스의 본질적인 한계다. 그렇다고 일대다 관계에서 살펴봤던 것처럼, 하나의 컬럼에 여러 상품 ID 쉼표로 구분해서 넣는 "1,2,3" 같은 방식은"제1 정규형"을 위반하고, 인덱스를 사용할 없으며, 데이터 수정이 복잡해지는 모든 면에서 최악의 설계다. 컬럼(product_id_1, product_id_2, ...)을 두는 또한 확장성이 없고 문제가 많다.

 

이것이 바로 관계형 데이터베이스의 한계이자 특징이다. 테이블의 컬럼은 원자적인(atomic) 하나만 가져야 한다는 강력한 제약 덕분에 데이터 정합성을 지킬 있지만, 대가로 다대다 같은 유연한 관계는 직접 표현하지 못하는 것이다. 이것은 관계형 데이터베이스가 외래 하나로 단일 행을 가리키는 방식으로 관계를 맺기 때문에 발생하는 구조적인 한계다.

 

 

다른 패러다임에서는??

1) JAVA

class Order {
	List<Product> products; // 주문은 상품 목록을 가진다.
}
class Product {
	List<Order> orders; // 상품은 주문 목록을 가진다.
}
  • 각 객체가 상대방 객체의 목록(List)을 직접 참조하면 그만이다.

2) NoSQL

// 주문(Order) 문서
{
    "order_id": 1001,
    "ordered_at": "2025-08-15",
    "products": [ // 주문한 상품 정보를 배열로 포함
        { "product_id": 1, "name": "노트북", "price": 1500000 },
        { "product_id": 5, "name": "마우스", "price": 25000 }
    ]
}
  • MongoDB 같은 문서 데이터베이스에서는 하나의 "문서(Document)" 안에 다른 데이터를 배열 형태로 포함할 수 있어 "M:N" 관계를 비교적 쉽게 표현할 수 있다.