RDB M:N 관계

관계형 데이터베이스에서 M:N 관계에 대해 알아보자!

M:N 관계

M:N 관계는 한 쪽에서 보면 1:M 관계로 보인다. 반대 편에서도 마찬가지로 1:M 관계로 보여진다.

M:N 관계 예제

학생과 과목이라는 테이블이 있을 때 학생이 여러 개 과목을 수강하는 상황을 가정해보자.

학생 입장에서는 여러 개 과목을 수강할 수 있고, 과목 입장에서는 여러 학생이 해당 과목을 선택할 수 있다. 양쪽에서 모두 1:M 관계로 볼 수 있으므로 M:N 관계가 성립된다.

개념상으로는 M:N이 가능하다.

아래 이미지는 학생과 과목이 M:N으로 관계를 맺고 있다.

학생이 여러 과목을 수강 가능하다.

M:N 관계를 테이블로 표현 시 문제점

🚨 M:N 관계를 풀어서 학생 테이블과 과목 테이블로 표현해보면 PK 중복 문제가 발생한다.

기존 두 테이블로는 M:N 관계 표현 불가능

M:N 관계는 양쪽에서 PK 중복 문제가 발생하기 때문에 기존 두 개의 관계형 테이블로는 표현할 방법이 없다.

💡 관계라는 것은 테이블의 일반 속성끼리 연결해서 관계를 맺는 것이 아니라, PK와 FK 간의 연결을 통해 관계를 맺는 것이다. 즉, 관계를 위해선 FK 가 필요하다.

💡 M:N 관계에 참여하는 두 객체의 테이블끼리는 선천적으로 관계가 없다. 각 테이블은 스스로 존재한다. 그런데 이들 사이에 어떤 관계를 맺어줌으로써 M:N 관계를 테이블로 표현할 수 있게 된다.

어떻게 M:N 관계를 테이블로 표현할 것인가?

결국 M:N 관계를 테이블로 표현하려면 또 하나의 테이블이 필요하다.

학생과 과목의 M:N 관계를 표현하기 위해 수강 테이블이 등장

학생과 과목은 각자 스스로 존재하는 엔티티(개념, 테이블)이다. 그러면 수강 테이블은 스스로 존재하는 테이블일까?

NO. 수강 테이블은 학생과 과목 사이에서 행위(비즈니스 로직)를 정의하기 위해 등장한 테이블이다.

⭐️ M:N 관계는 비즈니스 관계이다.

비즈니스 관계라는 것은 상대방 간의 어떤 계약 관계를 맺어서 움직인다는 것이다.

즉, 주어, 목적어, 동사가 포함되는 비즈니스 행위가 일어나서 M:N 관계를 형성하는 것이다.

예를 들어, 학생(주어)이 과목(목적어)을 수강(동사)합니다. 라는 요구사항 또는 비즈니스 행위가 존재할 때 M:N 관계를 학생, 과목, 수강 테이블로 표현 가능해지는 것이다.

M:N 관계에서는 테이블을 읽는 방법을 배우는 것이 매우 중요하다.

학생과 과목은 관계가 없다.

선천적으로 스스로 존재하는 학생과 과목에는 사실 어떠한 관계도 없다. 하지만 이 객체들이 관계를 맺는 순간이 온다.

언제???

비즈니스 로직(학생이 과목을 수강합니다.)이 들어오는 순간 학생과 과목 사이의 비즈니스 행위로 인해 관계가 맺어지는 것이다.

⭐️ M:N 관계라는 것은 어떤 행위가 있을 적에, 즉 비즈니스 로직이 나타날 때 스스로 존재하던 객체 간의 관계가 맺어지는 것이다.

기존 객체끼리 M:N 관계를 억지스럽게 테이블로 표현하려다 보니 PK 중복 문제가 발생했었다. 이것은 두 객체간의 비즈니스 행위를 정의하는 어떤 테이블이 생략됐기 때문에 발생한 문제였던 것이다.

Master Table

명사로서 스스로 존재할 수 있는 객체(테이블)들을 Master Table이라고 한다.

  • ex: 학생, 과목, 고객, 상품

Relation Table

동사로서 비즈니스 행위를 정의하여 M:N 관계를 표현하는 테이블을 Relation Table이라고 한다. 참고로 관계(Relation) 테이블이 명사로서 마스터 테이블로 해석될 때도 존재한다.(관계 테이블의 PK가 또 다른 관계 테이블의 FK로 참조되는 경우이다.)

  • ex: 수강, 주문

💡 REG_DATE

참고로 비즈니스 행위를 정의하는 관계(Relation) 테이블은 항상 날짜 컬럼(REG_DATE)이 필수 요소이다. 누가 무엇을 언제 ~를 했다. 를 표현할 때 언제를 날짜 컬럼이 맡게 된다.

M:N은 결국 쌍방 1:M 관계로 해석된다.

  • 학생 - 수강 테이블 간의 관계는 1:M 관계이다.
  • 과목 - 수강 테이블 간의 관계는 1:M 관계이다.

결국 두 개의 관계를 합쳐서 M:N 관계로 해석이 되는 것이다.

M:N 관계로 해석하기 전에 살펴봐야 하는 것

  • 각 Master 테이블 간 쌍방으로 1:M 관계가 없는지 살펴봐야 한다.
  • 1:M 관계가 없다면 두 Master 테이블은 M:N 관계인 것이다.

M:N 관계 테이블의 기본키 체계

M:N 관계 테이블의 PK는 어떻게 잡아야 할까?

결과부터 말하자면, 비즈니스 특징에 따라 다르다.

독립형 PK

FK 의 중복을 허용해야 하는 비즈니스 상황에서는 독립형 PK를 사용한다.

고객은 동일한 상품을 여러 번 구매할 수 있다.

중복을 허용하는 상황에서는 PK를 독립적으로 설정해주자.

상속형 PK

FK의 중복을 허용하지 않는 비즈니스 상황에서는 상속형 PK를 사용한다.

학생은 동일한 과목을 중복으로 수강할 수 없다.

중복을 허용하지 않는 상황에서는 FK를 묶어서 복합키를 PK로 설정해주자.

💡 설계 시 주의 사항

하나의 테이블은 하나의 객체나 사물을 모델링 하는 것이다. 두 개 이상의 객체를 하나의 테이블로 모델링 하는 순간 잘못된 설계를 하는 것이다.

만약 관계 테이블에 참여하고 있는 마스터 테이블이 많다면???

하나의 레코드를 식별하기 위해 WHERE 절에 엄청 많은 FK 를 조건으로 적용해야지 식별할 수 있을 것이다.

1
2
3
SELECT *
FROM 수강
WHERE 학생ID='1' and 과목ID='c' and f3='2' and f4 ='k'and ...;

실무에서는 관계 테이블을 형성하고 있는 마스터 테이블이 단순히 2개인 경우만 있는 것이 아니라 무수히 많을 수도 있다.

이런 경우 WHERE절에서 간단히 조회하기 위해 보조키(대체키, alternate key)를 선언해줘서 하나의 레코드를 식별하는 데 편함을 얻을 수 있다. 단, 상속형 PK 를 기본키로 사용하여 FK의 중복을 허용하지 않는다는 것을 전제로 해야 한다.

seq 라는 보조키를 선언해줬다.
1
2
3
SELECT *
FROM 수강
WHERE seq=5;

보조키(대체키)는 PK의 특징을 모두 만족하지만 PK는 아니다.

UNIQUE 하면서 NOT NULL을 모두 만족하지만 PK로 등록이 안된 키이다.

보조키는 관계 테이블의 조건절을 간단하게 만들어 조회를 편리하게 한다.