577. 다대다(M:N) 관계 해소 및 교차 릴레이션 (Intersection Entity) 분해

⚠️ 이 문서는 관계형 데이터베이스(RDBMS) 설계(ERD)에서 학생과 수강 과목처럼 '여러 명이 여러 개를 선택할 수 있는 다대다(M:N) 관계'를 DB 테이블로 직접 구현하는 것은 물리적으로 불가능하며 데이터 중복의 재앙을 낳기 때문에, 중간에 '교차 테이블(매핑 테이블)'을 쑤셔 넣어 일대다(1:N) 관계 두 개로 강제로 찢어발기는(분해) 정규화의 핵심 기술을 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: RDBMS의 교리상 하나의 칸(Cell)에는 여러 개의 값을 넣을 수 없다. '학생' 테이블에 '수강과목1, 수강과목2...' 식으로 컬럼을 무한정 늘리거나 쉼표로 구분해 넣는 것은 1정규형(1NF) 위반이다.
  2. 가치: 중간 매핑 테이블을 만들면 학생 정보나 과목 정보가 불필요하게 1,000번씩 중복 저장되는 것을 막아주어(이상 현상 방지), 완벽하게 깔끔하고 정합성이 유지되는 데이터베이스 스키마를 완성할 수 있다.
  3. 기술 체계: 논리적 모델링의 다대다(M:N) 선(Line)을 끊어버리고, 그 자리에 **교차 엔티티(Intersection Entity, 매핑 테이블)**를 세운 뒤 양쪽의 기본 키(PK)를 가져와 자신의 복합 기본 키(Composite PK)이자 외래 키(FK)로 삼아 1:N 관계로 변환한다.

Ⅰ. 다대다(M:N) 관계의 모순과 정규화 위반

하나의 칸에 두 개의 값을 넣을 수 없다는 RDBMS의 헌법.

  1. 상황 가정 (학생과 과목):
    • 홍길동 학생은 '수학', '영어', '과학' 3과목을 듣는다.
    • '수학' 과목은 홍길동, 김철수, 이영희 3명이 듣는다. 전형적인 다대다(M:N) 관계다.
  2. 직접 구현의 끔찍한 실패:
    • 방법 A (컬럼 늘리기): 학생 테이블에 과목1, 과목2, 과목3 컬럼을 뚫는다. 누군가 10과목을 신청하면 컬럼이 모자라 테이블을 또 뜯어고쳐야 한다. (구조의 경직성)
    • 방법 B (쉼표로 넣기): 수강과목 컬럼에 "수학, 영어, 과학"이라고 적는다. 나중에 "수학 듣는 사람 다 찾아!"라고 쿼리하려면 LIKE '%수학%'을 써야 해서 인덱스도 못 타고 DB가 뻗어버린다. (1정규형 위반)
    • 방법 C (줄 늘리기): 홍길동을 3줄(Row)로 복사해서 저장한다. 홍길동의 '전화번호'나 '주소' 데이터가 3번이나 똑같이 중복(Data Redundancy) 저장되어 용량이 낭비되고 갱신 이상(Update Anomaly)이 터진다.

📢 섹션 요약 비유: 서류 가방(RDBMS)에 규칙이 있습니다. "1개의 봉투 안에는 반드시 1장의 서류만 넣어야 한다(원자성)." 학생 봉투에 과목 서류 3장을 우겨넣으려 하니 봉투가 찢어지고(1정규형 위반), 학생 봉투를 3개 만들어서 1장씩 넣자니 학생의 신상 정보(이름, 주소)까지 3번이나 반복해서 베껴 적어야 하는(중복 낭비) 끔찍한 딜레마입니다.


Ⅱ. 교차 릴레이션 (Intersection Entity)의 투입

M:N을 1:N 2개로 찢어발기는 마법의 다리(Bridge).

  1. 매핑 테이블(Mapping Table)의 생성:
    • 논리적 ERD에 있던 학생과 과목 사이의 M:N 실선을 가위로 자른다.
    • 그 한가운데에 **수강 (Enrollment)**이라는 새로운 교차 엔티티(테이블)를 떡 하니 짓는다.
  2. PK의 상속과 1:N 분해:
    • 새로 만든 수강 테이블은 스스로 고유한 ID를 갖지 않는다.
    • 양쪽 부모 테이블에서 학생ID(PK)과목ID(PK)를 빌려와(외래 키, FK), 이 두 개를 합쳐서 자신의 '복합 기본 키(Composite PK)'로 삼는다.
    • 결과: 학생수강 테이블은 1:N 관계가 되고, 과목수강 테이블도 1:N 관계가 된다. 완벽한 RDBMS 표준 구조로 재탄생했다.
  3. 데이터의 깔끔한 분리:
    • 이제 학생 테이블에는 홍길동의 이름과 주소가 딱 1번만 저장된다.
    • 수강 테이블에는 [학생ID: 101, 과목ID: 99], [학생ID: 101, 과목ID: 100] 처럼 얇고 가벼운 ID 숫자들만 3줄 저장된다. 중복의 저주가 완벽하게 풀렸다.

📢 섹션 요약 비유: M:N 관계는 한국과 일본 사이에 다리가 없어서 배를 타고 각자 남의 땅으로 무질서하게 헤엄쳐 가는 혼돈의 바다입니다. 교차 릴레이션(매핑 테이블)은 바다 한가운데에 만든 '대마도(인공섬)'입니다. 이제 한국 사람(학생)은 대마도로 가는 다리(1:N)를 건너고, 일본 사람(과목)도 대마도로 가는 다리(1:N)를 건너서, 오직 대마도라는 통제된 공간(수강 테이블) 안에서만 1:1로 만나서 거래(데이터 연결)를 하게 만드는 완벽한 교통정리입니다.


Ⅲ. 교차 엔티티의 진화: 비즈니스 속성의 추가

단순한 다리를 넘어 스스로 독자적인 생명력을 갖는다.

  1. 순수 교차 릴레이션의 한계:
    • 수강 테이블이 학생ID과목ID 2개만 가지고 있으면 "홍길동이 수학을 듣는다"는 사실만 알 수 있다.
    • 그런데 학사팀에서 "홍길동의 수학 '중간고사 점수'와 '결석 횟수'는 어디 저장하죠?"라고 묻는다.
    • 학생 테이블에 넣을 수도 없고(영어 점수는 다르니까), 과목 테이블에 넣을 수도 없다(철수 점수는 다르니까).
  2. 새로운 속성(Attribute)의 품기:
    • 이 점수나 결석 횟수 같은 데이터는 오직 "홍길동이 수학을 수강할 때"만 발생하는 파생 데이터다.
    • 따라서 이 속성들은 중간 다리인 수강(교차 엔티티) 테이블의 뱃속에 새로운 컬럼으로 집어넣어야 한다. (학생ID, 과목ID, 중간고사점수, 기말고사점수, 출석률)
  3. 완벽한 독립 개체(Entity)로의 승격:
    • 단순한 매핑용 더미 테이블로 시작했던 수강 테이블이, 자기만의 비즈니스 데이터(점수, 학점)를 듬뿍 품으면서 학사 관리 시스템에서 가장 중요한 핵심 엔티티(트랜잭션 테이블) 중 하나로 신분 상승하게 된다.

📢 섹션 요약 비유: 처음에 대마도(수강 테이블)는 그저 한국인(학생ID)과 일본인(과목ID)이 만났다는 '도장'만 찍어주는 텅 빈 콘크리트 다리였습니다. 그런데 둘이 자주 만나다 보니 돈 거래가 생깁니다. 그래서 대마도 위에 '환전소'도 짓고 '면세점'도 지어서, 그들이 거래한 금액과 물품 내역(중간고사 점수, 출석률)을 대마도 장부에 직접 기록하기 시작합니다. 단순한 징검다리가 거대한 국제 무역의 중심지(독립 엔티티)로 진화하는 과정입니다.