문서 읽는 데 59분 · B1

B-1: 데이터 모델링 개요 — 표는 왜 그렇게 생겼을까, 종이 위 설계의 시작

목차 48
전체 24강 중 3강 · 데이터베이스
난이도 · 입문

ℹ️Oracle SQL로 SQLD 자격증을 대비하며 실전 SQL을 쌓는 트랙이에요. 프로그래밍 경험이 없어도 시작할 수 있고, 부트캠프에서는 자바 기초 다음·스프링 부트 직전에 배치하길 권해요.

안녕하세요, 데이터베이스의 세계로 함께 가는 홍순구 튜터입니다. 다시 만나서 반가워요.

지난 시간엔 이미 만들어져 있던 member·post 표를 들여다보며 테이블·행·열, 그리고 기본키를 정식으로 만났죠. SELECT * FROM member 한 줄로 회원 8명이 또렷한 표로 돌아오는 걸 눈으로 확인했고요. 그때 마지막에 제가 살짝 던진 질문이 있었어요. "그 표들은 왜 하필 그렇게 생겼을까?"

오늘은 그 질문에 답하러 갑니다. 한 발 물러나서, 누군가 그 표를 처음 만들기 전에 했던 일 — 회원·게시물·댓글·팔로우 같은 현실의 대상을 어떤 표로, 어떤 관계로 나눌지 종이 위에 먼저 그려보는 작업을 시작해요. 이걸 데이터 모델링이라고 부릅니다. 오늘부터 우리는 표를 읽는 사람에서 표를 설계하는 사람으로 넘어갑니다.

텍스트
 오늘의 여정 — 종이 위에 데이터를 그리는 법

  ① 데이터를 그림으로 그린다 — 모델링의 의미
  ② 무엇을 담을 건가 — 엔터티(Entity) 발견
  ③ 각 대상이 뭐를 갖는가 — 속성(Attribute) 정의
  ④ 어떤 관계로 이을 건가 — 관계(Relationship) 표현
  ⑤ 같은 데이터를 다른 관점으로 — 모델 3계층(개념·논리·물리)
  ⑥ 설계는 변경에 강해야 한다 — 데이터 독립성과 정규화 맛보기
  ⑦ 인스타그램을 모델링하자 — 3계층 관점에서 한눈에
        │
        
   현실  종이 위 설계도  SQL 테이블로 이어지는 길 잡기

종이와 펜만 있으면 됩니다. 오늘은 SQL 을 새로 짜는 시간이 아니라, SQL 을 짜기 전에 무엇을 그려야 하는지를 배우는 시간이에요.

💡 오늘 수업의 핵심 — "현실을 표로 옮기기 전에, 무엇을·어떤 특성으로·어떻게 연결할지 종이 위에서 먼저 설계한다"

🎯 학습 목표

  • 데이터 모델링이 무엇이고 왜 필요한지 이해하고, 모델링의 3대 특징(추상화·단순화·명확화)을 설명할 수 있다.
  • 모델링의 3요소(엔터티·속성·관계)가 각각 무엇을 가리키는지 구분할 수 있다. (오늘은 '의미'만 잡고, 셋의 상세는 다음 Step 들에서 하나씩)
  • SQLD 1과목 "데이터 모델링의 이해" 의 출발점인 모델링 개념과 특징을 시험 관점에서도 정리할 수 있다.

Step 1: "데이터를 그림으로 그린다 — 모델링의 의미"

지난 시간에 우리가 본 member 표와 post 표를 떠올려 보세요. 회원은 member_id·username·nickname·bio 라는 열을 가졌고, 게시물은 member_id 라는 열로 회원과 이어져 있었죠. 그 표들은 우연히 그렇게 생긴 게 아니에요. 누군가 "회원이라는 표는 이런 열을 갖고, 게시물 표는 회원과 이렇게 이어지게 만들자"라고 미리 설계해 둔 결과물입니다.

바로 그 설계 과정이 오늘의 주인공, 데이터 모델링(data modeling) 이에요. 현실 세계의 대상들 — 회원, 게시물, 댓글, 좋아요, 팔로우 — 을 데이터베이스에 담을 수 있는 구조로 옮기는 작업을 말합니다.

집을 짓기 전에 도면을 먼저 그리는 이유

집을 지을 때를 생각해 봅시다. 인부들이 곧바로 망치를 들고 벽돌을 쌓기 시작할까요? 절대 아니죠. 먼저 건축 설계도(도면)를 그립니다. 방은 몇 개고, 문은 어디에 달고, 화장실 배관은 어떻게 지나갈지를 종이 위에서 다 정한 다음에 공사를 시작해요.

옷을 만들 때도 똑같아요. 비싼 천을 바로 가위로 자르지 않습니다. 먼저 종이로 패턴(본)을 떠서 모양을 잡아두고, 그 본대로 천을 재단하죠. 한 번 자른 천은 되돌릴 수 없으니까요.

데이터베이스도 마찬가지예요. 곧바로 CREATE TABLE 로 표를 만들어 버리면, 나중에 "아, 이 열이 빠졌네", "이 두 표를 잘못 이었네" 싶어도 이미 데이터가 잔뜩 쌓여서 고치기 힘듭니다. 그래서 표를 만들기 전에, 종이 위에 설계도를 먼저 그리는 거예요. 이 설계도를 모델(model) 이라고 부릅니다.

텍스트
   현실을 SQL 테이블로 옮기는 세 걸음

   [1] 현실 세계  (복잡한 진짜 세상)
         회원이 있고, 게시물을 쓰고, 서로 팔로우한다
          │
          │   추상화: 핵심만 추려 그림으로 정리
          
   [2] 종이 위 설계도 = 모델  (오늘 배우는 '모델링')
         회원 = 표 한 장, 게시물 = 표 한 장, 둘을 연결
          │
          │   구현: CREATE TABLE 로 실제로 생성
          
   [3] SQL 테이블  (지난 시간에 본 결과물)
         member 표, post 표, 그리고 실제 데이터

맨 위의 복잡한 현실에서 맨 아래의 SQL 표로 바로 건너뛰지 않습니다. 가운데에 "종이 위 설계도"라는 다리를 한 번 놓는 것, 그게 모델링이에요. 우리가 지난 시간에 만난 표들은 이 길의 맨 아래 결과물이었던 거죠.

모델링의 3대 특징 — 추상화·단순화·명확화

그럼 모델링은 구체적으로 어떤 일을 하는 걸까요? 모델링에는 세 가지 핵심 특징이 있어요. ★빈출 — 이 세 가지는 SQLD 1과목에서 단골로 묻는 내용이니, 의미를 확실히 잡고 갑시다.

추상화(abstraction) 는 현실의 수많은 정보 중에서 핵심만 추려내는 것이에요. 한 사람에게는 키, 몸무게, 좋아하는 음식, 즐겨 보는 영화까지 정보가 끝도 없죠. 하지만 인스타그램 회원을 표로 담을 땐 그걸 다 적지 않아요. 서비스에 필요한 것만 — 아이디, 이름, 자기소개 정도만 — 골라냅니다. 이렇게 군더더기를 덜어내고 본질만 남기는 게 추상화예요.

단순화(simplification) 는 복잡한 현실을 누구나 이해할 수 있는 약속된 규칙으로 줄이는 것입니다. 현실의 "회원이 게시물을 올린다"라는 복잡한 행위를, 화살표 하나와 표 두 개라는 단순한 약속으로 표현해요. 약속된 기호로 줄여두면, 처음 보는 사람도 그림만 보고 구조를 읽어낼 수 있죠.

명확화(clarification)누가 봐도 똑같은 뜻으로 읽히게 분명히 하는 것이에요. "회원"이라는 한 단어도 사람마다 다르게 해석할 수 있잖아요. 가입만 한 사람? 게시물을 올린 사람? 모델에서는 이런 애매함을 없애고, 정확히 무엇을 가리키는지 모두가 같은 뜻으로 이해하도록 분명하게 정의합니다.

세 가지를 한 줄로 묶으면 이래요. 핵심만 추려서(추상화), 약속된 규칙으로 줄이고(단순화), 누가 봐도 같은 뜻이 되게(명확화) 현실을 그려내는 것 — 그게 데이터 모델링입니다.

표를 읽는 사람에서, 표를 설계하는 사람으로

지난 시간까지 우리는 이미 만들어진 표를 읽었어요. 이제부터는 그 표를 직접 그리는 쪽으로 넘어갑니다. 그러려면 종이 위에 무엇을, 어떻게 그릴지 도구가 필요하겠죠?

그 도구가 바로 모델링의 3요소 — 엔터티·속성·관계 입니다. 오늘은 이 셋이 각각 무엇을 가리키는지 이름과 의미만 먼저 만나두고, 하나하나 자세히 그려보는 건 이어지는 Step 들에서 해요. 다음 Step 에서 "무엇을 담을 것인가"인 엔터티부터 시작합니다.

💡 한 줄 정리

데이터 모델링은 현실을 데이터베이스 구조로 옮기는 설계 작업이다. 집 짓기 전 도면처럼, 표를 만들기 전에 종이 위에 먼저 그린다. 핵심 특징 세 가지는 추상화(핵심만 추리기)·단순화(약속된 규칙으로 줄이기)·명확화(누가 봐도 같은 뜻).

🙋 학생 질문 — "튜터님, 지난 시간에 표가 이미 다 만들어져 있던데, 왜 설계를 따로 배워요?"

좋은 질문이에요. 지난 시간 그 표들이 처음부터 존재했던 건 아니거든요. 누군가가 강의를 준비하면서 "회원 표에는 어떤 열을 둘까, 게시물은 회원과 어떻게 이을까"를 먼저 설계해서 만들어 둔 거예요. 여러분이 직접 인스타그램 같은 서비스를 만든다면, 그 누군가가 바로 여러분이 됩니다.

그리고 설계를 제대로 안 하면 나중에 크게 고생해요. 예를 들어 회원 정보와 게시물을 한 표에 다 욱여넣으면, 회원이 게시물을 100개 올릴 때마다 그 회원의 이름·자기소개가 100번 반복돼서 들어갑니다. 회원이 이름을 바꾸면 100군데를 다 고쳐야 하고, 한 군데라도 빠뜨리면 데이터가 어긋나 버리죠. 이런 사고를 미리 막으려면, 표를 만들기 전에 "어떻게 나눠 담을지"를 종이 위에서 충분히 고민해야 해요.

지난 시간에 회원과 게시물을 왜 따로 담는지 잠깐 이야기했던 거 기억하시죠? 그 "왜 나눠 담는가"를 제대로 파는 게 바로 모델링이에요. 그래서 표를 읽을 줄 아는 것과는 별개로, 표를 설계하는 법을 따로 배우는 겁니다.


Step 2: "무엇을 담을 건가 — 엔터티(Entity) 발견"

종이 위에 설계도를 그리기로 했어요. 그럼 가장 먼저 무엇부터 정해야 할까요? "이 서비스가 도대체 무엇을 다루는 서비스인지"부터 정해야 합니다. 연극 대본을 쓸 때를 떠올려 보세요. 줄거리를 쓰기 전에 먼저 등장인물 목록 — 주인공은 누구고, 상대역은 누구고, 조연은 누구인지 — 을 정하잖아요? 데이터 모델링도 똑같아요. 인스타그램이라는 무대에 어떤 등장인물(대상)이 올라오는지부터 골라냅니다.

엔터티 — 데이터로 관리할 가치가 있는 대상

이렇게 데이터로 관리할 가치가 있는 현실의 대상을 엔터티(entity) 라고 불러요. 한국어로는 흔히 '개체'라고 옮깁니다. 회원, 게시물, 댓글처럼 "우리 서비스가 저장하고 다뤄야 하는 무언가"가 바로 엔터티예요.

여기서 잠깐, 지난 시간을 떠올려 봅시다. 우리가 SELECT * FROM member 로 회원 8명을 표로 봤죠. 그 member 표 — 사실 그건 결과물이었어요. 표가 먼저 있었던 게 아니라, 누군가 "회원이라는 관리 대상을 둬야겠다"고 정한 다음에 그걸 표로 옮긴 거예요. 그러니까 표보다 먼저 있었던 건 Member 라는 엔터티입니다.

텍스트
   엔터티가 먼저, 표는 그 다음

   [먼저]  Member 라는 엔터티 (관리할 대상)
              "회원을 데이터로 다뤄야겠다"
                 │
                 │   모델링: 무엇을 담을지 정함
                 
   [나중]  member 표 (지난 시간에 본 것)
              member_id · username · nickname · bio

인스타그램의 등장인물 다섯을 골라내자

그럼 인스타그램에는 어떤 엔터티가 있을까요? 화면을 떠올리며 하나씩 "이건 관리할 대상인가?"를 물어봅시다.

  • 회원이 있어요. 가입하고 로그인하는 사람들이죠. → Member(회원)
  • 회원이 사진과 글을 올려요. → Post(게시물)
  • 게시물 밑에 댓글이 달려요. → Comment(댓글)
  • 마음에 드는 게시물에 좋아요를 눌러요. → Like(좋아요)
  • 다른 회원을 팔로우해서 소식을 받아요. → Follow(팔로우)

이렇게 다섯이 인스타그램의 핵심 등장인물이에요. 종이 위에 박스 다섯 개로 그려두면 이렇게 됩니다.

텍스트
   인스타그램의 다섯 엔터티

   ┌──────────┐
   │  Member  │── 회원 (가입한 사람)
   └──────────┘
   ┌──────────┐
   │  Post    │── 게시물 (사진 + 글)
   └──────────┘
   ┌──────────┐
   │  Comment │── 댓글
   └──────────┘
   ┌──────────┐
   │  Like    │── 좋아요
   └──────────┘
   ┌──────────┐
   │  Follow  │── 팔로우 (회원 간 구독)
   └──────────┘

★빈출 — 엔터티가 무엇인지, 그리고 엔터티를 어떻게 분류하는지는 SQLD 1과목에서 단골로 나오는 주제예요. "엔터티 = 관리할 가치가 있는 대상" 이 한 줄을 확실히 잡고 갑시다.

혼자 설 수 있는 엔터티, 다른 것에 기대는 엔터티

다섯 엔터티를 늘어놓고 보면 미묘한 차이가 보여요. 회원(Member)은 혼자서도 존재할 수 있어요. 게시물을 한 개도 안 올린 회원도 회원이잖아요? 지난 시간 본 7번(taeyang)·8번(narae)이 그랬죠. 게시물이 0개여도 멀쩡한 회원이었어요.

그런데 댓글(Comment)은 어떨까요? 댓글은 반드시 어떤 게시물에 달리는 거예요. 달릴 게시물이 없으면 댓글이라는 게 존재할 수가 없죠. 즉 댓글은 게시물에 기대어 존재합니다. 이렇게 "혼자 설 수 있는 엔터티"와 "다른 엔터티가 있어야 비로소 존재하는 엔터티"가 있다는 것 — 오늘은 이런 구분이 있다는 것만 짚고 갈게요. 둘을 뭐라고 부르고 어떻게 나누는지는 B-2 에서 정식으로 다룹니다.

💡 한 줄 정리

엔터티(entity)는 데이터로 관리할 가치가 있는 현실의 대상이다. 인스타그램의 핵심 엔터티는 Member·Post·Comment·Like·Follow 다섯이다. 지난 시간 본 member 표는 Member 엔터티를 옮긴 결과물이다.

🙋 학생 질문 — "튜터님, 좋아요(Like)나 팔로우(Follow)도 엔터티예요? 그건 그냥 행동 아닌가요?"

아주 좋은 의문이에요. 좋아요나 팔로우는 분명 "누른다", "한다" 같은 행동처럼 느껴지죠.

판단 기준은 하나예요. "이걸 저장해 둬야 하는가?" 입니다. 좋아요를 한번 생각해 봅시다. 누가, 어떤 게시물에, 좋아요를 눌렀는지를 저장해 둬야 하잖아요? 그래야 나중에 "이 게시물은 좋아요가 몇 개인지", "내가 이 게시물에 좋아요를 눌렀는지"를 알 수 있으니까요. 저장하고 다뤄야 할 무언가가 생기는 순간, 그건 엔터티가 됩니다.

팔로우도 마찬가지예요. "누가 누구를 팔로우하는지"를 저장해 둬야 피드에 그 사람 글이 뜨겠죠. 그래서 행동처럼 보여도, 그 행동의 결과를 데이터로 남겨야 한다면 엔터티로 다룹니다. 반대로 그냥 스쳐 지나가고 저장할 필요 없는 행동이라면 엔터티가 아니에요.


Step 3: "각 대상이 뭐를 갖는가 — 속성(Attribute) 정의"

등장인물(엔터티)을 다 골랐어요. 그런데 박스에 이름만 적어두면 텅 빈 상자나 다름없죠. 이제 각 엔터티가 어떤 정보를 갖는지를 채워 넣을 차례예요. 회원이라면 아이디, 이름, 자기소개 같은 것들이요.

속성 — 엔터티가 갖는 특성

엔터티가 갖는 이런 항목 하나하나를 속성(attribute) 이라고 불러요. 회원의 아이디·이름·자기소개가 전부 속성이에요. 그리고 이 속성들이 표에서 뭐로 나타났는지 기억하시나요? 바로 열(column) 이에요. 지난 시간에 본 그 '열'이, 모델링 세계에서는 '속성'이라는 정식 이름을 얻습니다.

지난 시간 본 두 표의 열을 그대로 가져와 속성으로 정리하면 이래요.

텍스트
   Member 엔터티의 속성        Post 엔터티의 속성
   ┌──────────────────┐       ┌──────────────────┐
   │ * member_id      │       │ * post_id        │
   │   username       │       │   member_id      │
   │   nickname       │       │   caption        │
   │   bio            │       │   created_at     │
   └──────────────────┘       └──────────────────┘
   (* 표시가 식별자 — 각 행을 유일하게 구분하는 속성)

지난 시간 member 표에서 봤던 member_id·username·nickname·bio 가 그대로 Member 엔터티의 속성이 됐죠? 결과물(표의 열)을 거꾸로 따라 올라가니 설계(엔터티의 속성)가 보이는 거예요.

식별자 — 지난 시간 기본키가 정식 이름을 얻다

속성들을 보면 별표(*)를 붙여둔 게 하나씩 있죠. member_idpost_id 예요. 이 둘은 특별합니다. 여러 속성 중에서 각 행을 유일하게 구분해주는 속성이거든요.

이거, 지난 시간에 이미 만났어요. 바로 기본키(primary key) 입니다. member_id 가 회원 한 명 한 명을 겹치지 않게 구분해줬잖아요. 주민등록번호나 학번 같은 역할을 했죠. 모델링 세계에서는 이 기본키를 식별자(identifier) 라고 부릅니다. 식별, 즉 "누구인지 가려내는" 속성이라는 뜻이에요.

텍스트
   같은 것, 다른 이름

   지난 시간 (A-1)          이번 시간 (모델링)
   ─────────────           ───────────────
   열(column)             속성(attribute)
   기본키(PK)             식별자(identifier)

★빈출 — 식별자도 SQLD 1과목 단골이에요. 식별자에 어떤 종류가 있는지, 두 개 이상의 속성을 묶어 식별자로 쓰는 경우는 어떻게 되는지 같은 깊은 이야기는 다음 모듈들에서 차차 다룹니다. 오늘은 "기본키 = 식별자, member_id 가 Member 의 식별자" 이 감각만 잡아두세요.

다른 엔터티를 가리키는 속성도 있다

Post 의 속성을 다시 보면 member_id 가 끼어 있죠. 이건 좀 특이해요. Post 자신의 정보(글 내용, 작성일)가 아니라, "이 게시물을 누가 썼는지" 즉 다른 엔터티(Member)를 가리키는 속성이거든요. 지난 시간 Step 6 에서 본 바로 그 연결입니다. 이렇게 다른 엔터티를 가리키는 속성은 다음 Step 4 의 '관계'에서 정식으로 다룹니다.

💡 한 줄 정리

속성(attribute)은 엔터티가 갖는 항목이고, 표에서는 열(column)로 나타난다. 그중 각 행을 유일하게 구분하는 속성이 식별자(identifier)이며, 이는 지난 시간 배운 기본키와 같다.

🙋 학생 질문 — "튜터님, 속성은 많을수록 좋은 거 아니에요? 정보가 많으면 좋잖아요."

직관적으로는 그렇게 느껴지죠. 그런데 속성을 무작정 늘리면 오히려 부담이 됩니다.

Step 1 에서 모델링의 특징으로 추상화 — "핵심만 추려내기"를 이야기했죠? 회원 한 사람에게는 키, 몸무게, 좋아하는 영화, 즐겨 듣는 노래까지 정보가 끝도 없어요. 그걸 다 속성으로 넣으면 어떻게 될까요? 관리할 게 폭발적으로 늘어나고, 정작 안 쓰는 정보가 공간만 차지합니다. 입력하는 사람도 매번 다 채워야 해서 번거롭고요.

게다가 불필요한 속성은 중복과 사고의 씨앗이 돼요. 안 쓰는 정보일수록 누군가 한 군데만 고치고 다른 데는 안 고쳐서 데이터가 어긋나기 쉽거든요. 그래서 "서비스에 정말 필요한 속성만" 골라 담는 게 좋은 설계예요. 정보가 많은 것과 잘 설계된 것은 다른 이야기랍니다.


Step 4: "어떤 관계로 이을 건가 — 관계(Relationship) 표현"

이제 마지막 도구예요. 엔터티(Step 2)를 고르고, 각자의 속성(Step 3)을 채웠어요. 그런데 엔터티들이 따로따로 떨어져 있으면 인스타그램이 안 돌아가요. 회원이 게시물을 올리고, 게시물에 댓글이 달리고, 회원끼리 팔로우하면서 서로 이어져야 비로소 서비스가 됩니다. 이 이어짐을 종이 위에 그리는 게 오늘의 마지막 일이에요.

관계 — 엔터티와 엔터티가 연결되는 방식

엔터티와 엔터티가 서로 연결되는 방식을 관계(relationship) 라고 불러요. 지난 시간 Step 6 에서 이미 맛봤죠. post 표의 member_idmember 표를 가리키면서, "이 게시물을 누가 썼는지"를 이어줬잖아요. 1번 게시물의 member_id 가 1이니까 jaehoon 이 쓴 글이었고요.

이걸 한 문장으로 바꾸면 이래요. "한 회원이 여러 게시물을 쓴다." 이게 바로 Member 와 Post 사이의 관계입니다. 그때 슬쩍 지나갔던 표끼리의 연결이, 이번 시간에 '관계'라는 정식 이름과 표기를 얻는 거예요.

관계 차수 — 1:1, 1:N, M:N

관계를 그릴 때 가장 중요한 게 몇 개가 몇 개와 이어지느냐예요. 이걸 관계 차수(cardinality), 우리말로 그냥 "차수"라고 합니다. 세 가지 모습이 있어요.

  • 1:1 (일대일) — 하나가 하나와만 이어짐.
  • 1:N (일대다) — 하나가 여러 개와 이어짐.
  • M:N (다대다) — 여러 개가 여러 개와 이어짐.

인스타그램에 대보면 금방 이해돼요. 먼저 회원과 게시물이요. 한 회원은 게시물을 여러 개 올릴 수 있지만, 게시물 하나는 한 회원만 쓴 거죠. 그래서 1:N 관계예요.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Member  │ 1 ────────< N  │   Post   │
   └──────────┘                └──────────┘
   한 회원(1)이 여러 게시물(N)을 쓴다

   까마귀발(──<)이 'N(여러 개)' 쪽을 가리킨다

게시물과 댓글도 마찬가지예요. 게시물 하나에 댓글이 여러 개 달리지만, 댓글 하나는 게시물 하나에만 달리죠. 역시 1:N 입니다.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Post    │ 1 ────────< N  │ Comment  │
   └──────────┘                └──────────┘
   한 게시물(1)에 여러 댓글(N)이 달린다

M:N — 여러 개가 여러 개와 이어질 때

좋아요(Like)는 좀 달라요. 한 회원이 여러 게시물에 좋아요를 누를 수 있고, 동시에 게시물 하나도 여러 회원에게서 좋아요를 받죠. 양쪽 다 '여러 개'예요. 이게 M:N(다대다) 입니다.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Member  │ M >──────< N   │   Post   │
   └──────────┘                └──────────┘
   회원도 여러 게시물에 좋아요,
   게시물도 여러 회원에게 좋아요  양쪽 다 여럿

팔로우(Follow)는 한층 더 흥미로워요. 회원이 여러 회원을 팔로우하고, 한 회원도 여러 회원에게 팔로우당하죠. 양쪽 다 여럿이니 M:N 인데, 특이하게도 같은 Member 끼리 이어지는 관계예요. 자기 자신과 이어진다는 뜻이 아니라, Member 라는 같은 엔터티 안에서 회원이 회원을 가리키는 거예요.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Member  │ M >──────< N   │  Member  │
   └──────────┘                └──────────┘
   회원이 다른 회원을 팔로우  같은 Member 엔터티끼리 맺는 M:N 관계 (Follow)

여기서 한 가지만 약속해요. M:N 관계를 실제로 표로 만들 땐 작은 요령이 필요한데(중간에 표를 하나 더 두는 방식이에요), 그건 한참 뒤 모듈에서 제대로 배웁니다. 지금은 "아, 좋아요랑 팔로우는 양쪽이 여럿인 M:N 관계구나" 하고 이름과 의미만 알아두면 충분해요. ★☆☆ 난이도, 가볍게 지나갑니다.

선택성 — 반드시 있어야 하나, 없어도 되나

관계에는 차수 말고 하나 더 봐둘 게 있어요. 반드시 있어야 하는 관계인지, 없어도 되는지예요. 이걸 선택성이라고 합니다.

지난 시간 7번(taeyang)·8번(narae) 회원 기억하시죠? 게시물이 한 개도 없었어요. 그러니까 "한 회원이 게시물을 쓴다"는 관계에서, 회원 입장에선 게시물이 0개여도 괜찮은 거예요. 게시물은 있어도 되고 없어도 되는, 선택적인 관계인 거죠. 반대로 게시물 입장에선 작성자(회원)가 반드시 있어야 하고요. 이렇게 "꼭 있어야 하나 / 없어도 되나"를 따지는 게 선택성이에요.

ERD 표기 — 까마귀발 기호 맛보기

위 그림들에서 ──< 라는 기호를 봤죠? 끝이 새 발처럼 세 갈래로 갈라진 모양이라 까마귀발(Crow's Foot) 표기라고 불러요. 이 갈라진 쪽이 'N(여러 개)' 방향을 가리킵니다. 이렇게 엔터티와 관계를 기호로 그린 그림 전체를 ERD(Entity-Relationship Diagram, 개체-관계 다이어그램) 라고 해요.

★빈출 — 관계 차수, 특히 1:N 과 M:N 을 구분하는 문제는 SQLD 단골이에요. ERD 정식 표기법의 자잘한 규칙들은 다음 모듈에서 더 다루니, 오늘은 "까마귀발이 여러 개 쪽" 정도만 기억해 두세요.

💡 한 줄 정리

관계(relationship)는 엔터티끼리 연결되는 방식이다. 차수에 따라 1:1·1:N·M:N 으로 나뉜다. 인스타에서 회원-게시물은 1:N, 좋아요와 팔로우는 M:N 이다. 까마귀발(──<) 기호가 'N(여러 개)' 쪽을 가리킨다.

🙋 학생 질문 — "튜터님, M:N 관계는 표로 어떻게 만들어요? 좋아요 표를 어떻게 그리죠?"

지금 그게 궁금한 게 아주 자연스러워요. 그런데 미리 말씀드리면, M:N 을 표로 푸는 건 살짝 요령이 필요해서 오늘 다루기엔 일러요.

힌트만 드리면 이래요. 회원과 게시물을 직접 잇는 대신, 둘 사이에 표를 하나 더 끼워 넣어요. "몇 번 회원이 몇 번 게시물에 좋아요를 눌렀다"를 한 줄씩 적는 표예요. 이렇게 하면 양쪽이 여럿인 M:N 관계도 깔끔하게 풀립니다. 사실 지난 시간 봤던 post 표의 member_id 가 1:N 을 푸는 방식이었던 것과 비슷한 발상이에요.

오늘은 "이런 관계가 있다"는 것까지만 알아두면 됩니다. 실제로 표로 풀어내는 법은 모델링을 더 배우고 나서, SQL 로 직접 표를 만들 때 제대로 익혀요. 그때 가면 "아, 그래서 그때 미뤄둔 거구나" 하실 거예요. 지금 당장 다 알아야 하는 게 아니니 안심하세요.


Step 5: "같은 데이터를 다른 관점으로 — 모델 3계층(개념·논리·물리)"

엔터티·속성·관계, 모델링의 3요소를 다 손에 넣었어요. 그런데 한 가지 의문이 생길 수 있어요. 우리가 지금까지 그린 그림 — Member 박스에 까마귀발로 Post 를 잇고 속성을 채운 그 ERD — 와, 지난 시간에 본 member 표(자료형까지 다 정해진 진짜 표)는 같은 걸까요, 다른 걸까요?

답은 "같은 데이터를 다른 추상화 수준으로 본 것"이에요. 똑같은 회원 데이터라도, 보는 사람과 단계에 따라 세 가지 다른 모습으로 그려집니다. 이걸 모델 3계층이라고 해요.

한 데이터를 세 단계로 — 개념 → 논리 → 물리

설계는 한 번에 끝나지 않아요. 큰 그림부터 잡고, 점점 구체적으로 내려갑니다. 마치 건축에서 "이 건물엔 방이 몇 개 필요해"(개념) → "각 방 크기와 문 위치"(논리) → "벽돌은 어느 회사 제품, 콘센트는 몇 개"(물리)로 점점 상세해지는 것과 같아요.

텍스트
   같은 데이터, 세 단계의 모습

   ┌─ [1] 개념 모델 (conceptual) — 기획자·분석가
   │       "무엇이 있고 어떻게 이어지나" · 특정 DB 기술과 무관 · ERD 로 그림
   │   
   ├─ [2] 논리 모델 (logical)    — 설계자
   │       테이블명·컬럼·식별자·관계 명세 · 아직 특정 DBMS 무관
   │   
   └─ [3] 물리 모델 (physical)   — 개발자
           Oracle 에 맞춘 자료형·제약까지 · 지난 시간 본 member 표가 이 결과물

맨 위 개념 모델(conceptual model) 은 기획자나 분석가의 관점이에요. "우리 서비스에 회원이 있고, 게시물이 있고, 회원이 게시물을 쓴다" 같은 큰 그림을 그립니다. 특정 데이터베이스 기술과는 무관해요. Oracle 이든 MySQL 이든 상관없이 "무엇이 있고 어떻게 이어지나"만 그리는 단계죠.

그리고 여기서 깜짝 사실 — 우리가 Step 2~4 에서 그린 그 인스타 ERD 가 바로 개념 모델이었어요. 자기도 모르게 개념 모델을 한 거예요.

가운데 논리 모델(logical model) 은 설계자의 관점입니다. 개념 모델의 큰 그림을 구체적인 테이블 명세로 옮겨요. 테이블 이름은 뭐고, 컬럼은 어떤 게 있고, 식별자는 무엇이고, 어떤 관계로 이어지는지를 또박또박 적습니다. 다만 아직 "Oracle 의 NUMBER 자료형" 같은 특정 DBMS 이야기는 안 해요. 어떤 DBMS 든 공통으로 통할 수준까지만 내려갑니다.

맨 아래 물리 모델(physical model) 이 개발자의 관점이에요. 이제 실제 Oracle 에 맞춰서 자료형(NUMBER·VARCHAR2)과 제약까지 다 정합니다. 지난 시간에 본 member·post 표 — 그게 바로 물리 모델의 결과물이었어요. 종이 위 설계도가 실제 DB 안의 진짜 표로 내려앉은 모습이죠.

비슷하지만 다른 — ANSI-SPARC 3층 스키마

여기서 이름이 비슷한 다른 분류를 하나 소개할게요. ★빈출 — SQLD 1과목에서 단골로 나오는 ANSI-SPARC 3층 스키마예요. 데이터베이스가 데이터를 세 겹으로 감싸 보여주는 구조를 말합니다.

텍스트
   ANSI-SPARC 3층 스키마

   ┌─ 외부 스키마 (external)   — 사용자별로 필요한 부분만 보는 창(뷰)
   │
   ├─ 개념 스키마 (conceptual) — 조직 전체의 통합 구조
   │
   └─ 내부 스키마 (internal)   — 디스크에 실제 저장되는 물리 방식

외부 스키마는 사용자별로 필요한 부분만 보여주는 창이에요. 마케팅 담당자는 회원의 이름과 가입일만 보면 되고, 굳이 비밀번호 컬럼까지 볼 필요 없죠. 이렇게 사용자마다 다르게 보여주는 부분 화면을 뷰(view)라고 부르는데, 정식 이야기는 한참 뒤 모듈에서 다룹니다.

개념 스키마는 조직 전체가 공유하는 통합 구조예요. 회원·게시물·댓글이 전부 어떻게 생겼는지 한 군데 모아둔 전체 지도죠. 내부 스키마는 그 데이터가 디스크에 실제로 어떻게 저장되는지를 다루는, 가장 밑바닥 물리 방식이에요.

⚠️ 헷갈리기 쉬운 지점: 모델 3계층의 '개념'과 ANSI-SPARC 의 '개념 스키마'는 이름은 비슷해도 다른 분류예요. 모델 3계층(개념·논리·물리)은 설계가 진행되는 단계를 나눈 거고, ANSI-SPARC(외부·개념·내부)는 DBMS 가 데이터를 세 겹으로 감싸 보여주는 구조를 나눈 거예요. 둘 다 "추상화 수준을 나눈다"는 정신은 같지만 별개 개념이니, 헷갈리지 않게 따로 기억해 두세요.

이 3층 구조가 왜 좋은지 — 한쪽이 바뀌어도 다른 쪽이 안 흔들리는 그 든든함은 다음 Step 에서 이어집니다.

💡 한 줄 정리

같은 데이터를 추상화 수준에 따라 개념(무엇이 있나)·논리(테이블 명세)·물리(실제 DBMS 자료형) 3계층으로 본다. Step 2~4 의 ERD 가 개념, 지난 시간 본 member 표가 물리의 결과물이다. ANSI-SPARC 3층(외부·개념·내부)은 이름이 비슷한 별개 분류다.

🙋 학생 질문 — "튜터님, 개념·논리·물리를 왜 굳이 나눠요? 그냥 바로 표 만들면 안 돼요?"

급할 땐 그렇게 하고 싶죠. 그런데 단계를 나누면 두 가지 큰 이점이 생겨요.

첫째, 각 단계에서 한 가지에만 집중할 수 있어요. 개념 단계에선 "회원과 게시물을 어떻게 이을까"라는 큰 그림만 고민하면 돼요. "자료형을 NUMBER 로 할까 VARCHAR2 로 할까" 같은 세세한 건 나중에 물리 단계에서 따로 정하니까, 머리가 덜 복잡하죠. 처음부터 큰 그림과 세부사항을 한꺼번에 정하려 들면 뒤죽박죽이 됩니다.

둘째, 기술이 바뀌어도 앞 단계를 재사용할 수 있어요. 예를 들어 "Oracle 로 만들려다 MySQL 로 바꾸자"가 되면, 자료형이 다른 물리 모델만 다시 그리면 돼요. "회원이 게시물을 쓴다" 같은 개념·논리 모델은 그대로 살아남죠. 단계를 안 나누고 한 덩어리로 만들었다면, 처음부터 통째로 다시 그려야 했을 거예요.


Step 6: "설계는 변경에 강해야 한다 — 데이터 독립성과 정규화 맛보기"

Step 5 끝에서 "3층 구조가 왜 좋은지"를 다음으로 미뤘죠. 이제 답할 차례예요. 좋은 설계의 핵심은 "변경에 강한 것"이에요. 서비스는 계속 바뀌거든요. 컬럼이 추가되고, 저장 방식이 바뀌고, 요구사항이 늘어나죠. 그때마다 모든 게 와르르 무너지면 안 되겠죠?

데이터 독립성 — 한쪽이 바뀌어도 다른 쪽은 그대로

Step 5 의 ANSI-SPARC 3층(외부·개념·내부)이 여기서 빛을 발해요. 층을 나눠두면, 한 층이 바뀌어도 다른 층이 영향을 안 받게 막을 수 있거든요. 이걸 데이터 독립성이라고 합니다. 두 종류가 있어요.

논리적 독립성은 논리 구조(테이블)가 바뀌어도 사용자(외부)가 받는 영향이 최소라는 뜻이에요. 회원 테이블에 새 컬럼을 하나 추가해도, 기존 화면을 보던 사용자는 아무 영향 없이 그대로 쓸 수 있죠. 물리적 독립성은 저장 방식(내부)이 바뀌어도 논리 구조는 그대로라는 뜻입니다. 디스크에 데이터를 더 빠르게 저장하는 방식으로 바꿔도, 테이블 구조는 손댈 필요가 없어요.

식당으로 비유해 볼게요. 주방을 싹 개조해서 더 빠른 조리 설비를 들여놨다(물리 변경)고 해서, 손님이 보는 메뉴판(외부)이 바뀌나요? 안 바뀌죠. 손님은 똑같은 메뉴판으로 똑같이 주문해요. 주방 사정과 손님 화면이 따로 노는 것 — 그게 데이터 독립성이에요. ★빈출 — 데이터 독립성의 목적이 SQLD 단골이니 "층을 나눠 변경 충격을 막는다"로 기억해 두세요.

정규화 맛보기 — 중복을 없애려고 표를 나누다

이제 지난 시간에 미뤄둔 약속을 지킬 차례예요. 지난 시간에 "회원이랑 게시물을 왜 한 표에 안 넣어요?"라는 질문이 있었죠. 오늘 그걸 정면으로 풀어봅니다.

만약 회원 정보와 게시물을 한 표에 다 욱여넣으면 어떻게 될까요? 한 회원이 게시물을 100개 올렸다고 해봐요. 그러면 그 회원의 이름이 100번 반복돼서 들어갑니다.

텍스트
   Before — 비정규 (한 표에 회원정보 + 게시물을 다 담기)

   ┌───────────┬───────────┬─────────────┐
   │ username  │ nickname  │ post_id     │
   ├───────────┼───────────┼─────────────┤
   │ jaehoon   │ jaehoon_n │ 1           │
   │ jaehoon   │ jaehoon_n │ 2           │  username·nickname 가
   │ jaehoon   │ jaehoon_n │ 3           │   게시물마다 반복!
   └───────────┴───────────┴─────────────┘
   문제: jaehoon 이 nickname 바꾸면  3 줄(100개면 100줄) 다 고쳐야 함
         한 줄이라도 빠뜨리면  데이터가 어긋남
텍스트
   After — 정규화 (표를 나눠 member_id 로 연결)

   ┌───────────┬───────────┐        ┌───────────┬───────────┐
   │ member_id │ nickname  │        │ post_id   │ member_id │
   ├───────────┼───────────┤        ├───────────┼───────────┤
   │ 1         │ jaehoon_n │        │ 1         │ 1         │
   └───────────┴───────────┘        │ 2         │ 1         │
                                    │ 3         │ 1         │
                                    └───────────┴───────────┘
   Member 표 = 회원 정보 한 번만 · Post 표 = member_id 로 연결
   효과: nickname 바꾸면  Member 표 한 줄만 고치면 끝

비정규 표를 보세요. jaehoon 이 닉네임을 '재훈'에서 다른 걸로 바꾸고 싶으면 100군데를 다 고쳐야 하고, 한 군데라도 빠뜨리면 같은 사람인데 닉네임이 둘로 갈라지는 사고가 납니다. 그래서 회원 정보는 Member 표에 한 번만 두고, 게시물은 Post 표에 따로 두고, member_id 로 잇는 거예요. 이렇게 하면 닉네임을 바꿔도 Member 표 한 줄만 고치면 끝이죠.

이렇게 중복을 없애려고 표를 나누는 것을 정규화(normalization)라고 불러요. ★빈출 — 정규화의 목적("중복 제거")도 시험에 자주 나옵니다. 오늘은 이 "중복 제거 = 정규화"라는 감각만 잡으면 충분해요. 정규화에 어떤 단계가 있고 어떤 규칙으로 나누는지, 중복을 방치하면 구체적으로 어떤 사고가 나는지 같은 정식 이야기는 더 뒤 모듈에서 제대로 다룹니다.

💡 한 줄 정리

데이터 독립성은 한 층이 바뀌어도 다른 층이 안 흔들리게 하는 것(논리적·물리적). 정규화는 중복을 없애려고 표를 나누는 것이다. 회원 정보를 게시물마다 반복하지 않고 Member 표에 한 번만 두면, 변경이 한 군데로 끝난다.

🙋 학생 질문 — "튜터님, 표를 너무 잘게 나누면 오히려 불편하지 않아요? 매번 이어 봐야 하잖아요."

날카로운 지적이에요. 맞아요, 거기에 트레이드오프가 있어요.

표를 나누면 중복은 확실히 줄어듭니다. 대신 "회원 이름과 게시물 내용을 같이 보고 싶다"고 하면, 나뉜 두 표를 다시 이어서 봐야 하는 수고가 생기죠. 나누면 중복은 줄지만, 이어 보는 품이 늘어나는 거예요. 둘은 서로 맞바꾸는 관계입니다.

그래서 무작정 잘게 나누는 게 정답은 아니에요. "중복을 얼마나 줄일지"와 "이어 보는 수고를 얼마나 감수할지" 사이에서 균형을 잡는 것 — 바로 그 균형 잡기가 모델링의 묘미예요. 이 트레이드오프를 어디까지 밀어붙일지, 때로는 일부러 중복을 허용하기도 하는데, 그런 깊은 이야기는 더 뒤 모듈에서 차근차근 다룹니다. 오늘은 "나눠서 중복을 없앤다"는 큰 방향만 잡아두면 돼요.


Step 7: "인스타그램을 모델링하자 — 3계층 관점에서 한눈에"

자, 오늘의 마지막 시간이에요. 엔터티·속성·관계, 그리고 모델 3계층까지 배운 도구를 전부 꺼내서, 인스타그램 전체를 한 번에 모델링해 봅시다. 흩어져 있던 조각들이 하나의 그림으로 모이는 순간이에요.

최종 ERD — 다섯 엔터티를 한 그림에 (개념 모델)

Step 2~4 에서 따로따로 그렸던 박스와 관계선을 한데 모으면 이런 개념 모델이 됩니다.

텍스트
   인스타그램 통합 ERD (개념 모델)

   ┌──────────┐  1      N  ┌──────────┐  1      N  ┌──────────┐
   │  Member  │──────────< │   Post   │──────────< │ Comment  │
   └──────────┘            └──────────┘            └──────────┘

   추가로 두 개의 M:N 관계가 더 있어요 (양쪽 다 여럿):
     Member  M >────< N  Post      Like   (회원이 게시물에 좋아요)
     Member  M >────< N  Member    Follow (회원이 회원을 팔로우)

   기호 읽기:
     1 ──< : 일대다  (한 회원이 여러 게시물 · 한 게시물에 여러 댓글)
     M >──< : 다대다 (좋아요 · 팔로우)

한 그림 안에 인스타의 뼈대가 다 들어 있죠. 한 회원이 여러 게시물을 쓰고(1:N), 한 게시물에 여러 댓글이 달리고(1:N), 회원과 게시물이 좋아요로 다대다로 얽히고(M:N), 회원끼리 팔로우로 다대다로 이어집니다(M:N). 이게 오늘 우리가 종이 위에 완성한 인스타그램의 설계도예요.

논리 스키마 스펙 — 테이블 명세표 (논리 모델)

개념 모델을 한 단계 내려서 논리 모델로 정리하면 이런 표가 됩니다. 각 엔터티가 어떤 테이블이 되고, 무엇으로 식별하며, 어디를 가리키는지를 또박또박 적어요.

테이블 주요 속성 식별자(PK) 가리키는 관계(FK)
Member username, nickname, bio member_id (없음 — 혼자 선다)
Post caption, created_at post_id member_id → Member
Comment content, created_at comment_id post_id → Post, member_id → Member
Like created_at (member_id + post_id) member_id → Member, post_id → Post
Follow created_at (follower + following) 둘 다 → Member

표를 보면 재미있는 게 보여요. Member 는 가리키는 관계가 없어요. 혼자 서는 엔터티니까요. 반면 Like 와 Follow 는 식별자가 두 속성을 묶은 모습이죠. 이건 M:N 관계를 풀어낼 때 쓰는 방식인데, 자세한 건 뒤에서 다룹니다. 여기서 자료형이나 길이(VARCHAR2(30) 같은 것)는 일부러 안 적었어요. 그건 다음 시간 도메인을 배울 때 채워 넣습니다.

종이 설계도에서 진짜 표로 — 그 다음 단계 예고

여기까지가 오늘 우리가 그린 개념·논리 모델이에요. 그럼 이걸 진짜 Oracle 표(물리 모델)로 만드는 건 언제 할까요? 바로 C 카테고리에서, SQL 의 CREATE TABLE 명령으로 직접 만듭니다. 오늘 그린 이 설계도가 그때 그대로 진짜 표로 내려앉아요.

💡 한 줄 정리

오늘 배운 엔터티·속성·관계를 인스타 전체에 적용하면, Member·Post·Comment·Like·Follow 5 엔터티의 통합 ERD(개념)와 식별자·관계를 명세한 논리 스키마가 나온다. 자료형까지 채운 물리 모델(실제 표)은 C 카테고리에서 CREATE TABLE 로 만든다.

🙋 학생 질문 — "튜터님, 이제 이걸 진짜 표로 어떻게 만들어요?"

오늘 그림까지 그렸으니 그게 궁금한 게 당연해요. 답을 미리 살짝 드리면, 곧 SQL 로 직접 CREATE TABLE 명령을 써서 표를 만들게 됩니다.

핵심은 이거예요. 오늘 종이 위에 그린 설계도가 그때 그대로 표가 돼요. 오늘 정한 "Member 엔터티, 식별자는 member_id, Post 와 1:N 관계" 같은 내용이, C 카테고리에서 CREATE TABLE member (...) 같은 SQL 한 덩어리로 옮겨지는 거죠. 설계를 제대로 해두면 표 만들기는 그 설계를 SQL 문법으로 받아 적는 일에 가까워요.

그러니 오늘 ERD 를 꼼꼼히 그려둔 게 헛수고가 아니에요. 그게 곧 진짜 데이터베이스가 됩니다. 표 만드는 SQL 문법 자체는 그때 차근차근 배우니, 지금은 "설계가 곧 표가 된다"는 흐름만 잡아두세요.


마무리

오늘 수고 많으셨어요! 지난 시간에 그냥 읽기만 했던 그 표가, 이제는 "누군가 종이 위에서 엔터티·속성·관계를 고민해서 만든 설계의 결과물"로 보이시죠? 표를 읽는 사람에서 표를 설계하는 사람으로 한 걸음 넘어왔습니다.

오늘 배운 핵심 세 가지

  • 💡 하나 — 데이터 모델링은 현실을 표로 옮기기 전 종이 위에 먼저 그리는 설계다. 3대 특징은 추상화(핵심만 추리기)·단순화(약속된 규칙으로 줄이기)·명확화(누가 봐도 같은 뜻).
  • 💡 — 모델링 3요소는 엔터티(무엇이 있나)·속성(엔터티의 특성, 표의 열)·관계(엔터티 간 연결, 1:N·M:N)다. 각 엔터티를 유일하게 구분하는 속성이 기본키이자 식별자다.
  • 💡 — 같은 데이터를 개념·논리·물리 3계층으로 본다. 그리고 중복을 없애려 표를 나누는 것이 정규화다.

다음 시간 예고

오늘은 인스타그램의 다섯 엔터티를 고르고 큰 그림을 그렸어요. 다음 시간엔 그 다섯을 하나하나 더 깊이 들여다봅니다.

먼저 엔터티를 어떻게 분류하는지 — 오늘 "혼자 서는 엔터티(Member)와 다른 것에 기대는 엔터티(Comment)"를 잠깐 짚었죠? 그 둘을 독립 엔터티·종속 엔터티라는 정식 이름으로 가릅니다.

그리고 엔터티 이름은 어떻게 짓는지(명명 규칙), 속성에도 종류가 있는지(기본·파생·다중·복합 속성), 속성이 가질 수 있는 값의 범위는 어떻게 정하는지(도메인 — 자료형·길이)까지 다뤄요. 오늘 미뤄둔 "자료형은 다음 시간에"가 바로 이 도메인 이야기예요. 종이와 펜은 그대로 들고 오시면 됩니다.


과제

오늘 과제는 SQL 을 짜는 게 아니라, 종이 위에 직접 설계하고 판단해 보는 거예요. 정답을 맞히는 것보다 "왜 그렇게 그렸는지"가 더 중요합니다.

[기초] 새 엔터티 하나를 발견해서 속성 적어보기

인스타그램에 새 기능을 하나 상상해 보세요. 예를 들어 24시간 뒤 사라지는 '스토리'나, 누가 좋아요를 누르면 뜨는 '알림' 같은 거요. 그 기능을 데이터로 다루려면 새 엔터티가 하나 필요하겠죠? 그 엔터티의 이름을 정하고, 가져야 할 속성을 3~4개 적어보세요. 그중 각 행을 유일하게 구분할 식별자도 하나 골라보세요. (예: Story 엔터티 → story_id(식별자), member_id, image_url, created_at)

[응용] 두 관계의 차수를 판단하고 그려보기

다음 두 관계가 각각 1:N 인지 M:N 인지 정해보세요. (1) Member–Comment (한 회원과 그 회원이 단 댓글들), (2) 좋아요로 이어지는 Member–Post (회원과, 그 회원이 좋아요 누른 게시물들). 각각 까마귀발 기호(──<)로 그리고, 왜 그 차수라고 판단했는지 이유를 한 줄씩 적어보세요. 힌트: "한쪽이 여러 개를 가질 수 있나?"를 양방향으로 물어보세요.

[심화] 비정규의 문제를 자기 말로 설명하기

팔로우(Follow)는 회원과 회원의 M:N 관계예요. 만약 이걸 표로 나누지 않고 "한 표에 회원 정보와 팔로우 관계를 다 담는다"면 어떤 문제가 생길까요? 한 회원이 닉네임을 바꾸는 상황을 예로 들어, 어떤 중복이 생기고 어떤 사고가 날 수 있는지 서술해 보세요. 그리고 그래서 정규화(표 나누기)가 왜 필요한지 자기 말로 정리해 보세요.


생각해볼 주제

1. 개념·논리·물리를 굳이 나누는 값어치

설계를 빨리 끝내고 싶으면 바로 물리 모델(진짜 표)로 직행하고 싶어집니다. 그런데도 현장에서는 개념 → 논리 → 물리로 단계를 나눠 설계해요. 바로 표로 가지 않고 중간에 두 단계를 두는 것이 어떤 상황에서 진가를 발휘할지(예: 도중에 DBMS 가 바뀌거나, 기획이 크게 흔들릴 때) 떠올려 보세요.

2. 추상화의 트레이드오프 — 무엇을 남기고 무엇을 뺄까

모델링의 첫 번째 특징이 추상화, 즉 "핵심만 추려내기"였죠. 그런데 무엇이 핵심인지는 칼로 자르듯 분명하지 않아요. 회원 엔터티에 속성을 너무 적게 담으면 어떤 문제가, 반대로 너무 많이 담으면 어떤 문제가 생길까요? 둘 사이에서 균형을 잡는 기준이 무엇일지 생각해 보세요.

3. M:N 을 그대로 두지 않고 푸는 설계의 이점

좋아요와 팔로우는 양쪽이 여럿인 M:N 관계였어요. 이런 관계를 직접 잇지 않고, 중간에 표를 하나 더 두는 방식으로 설계하면 어떤 이점이 생길지 상상해 보세요. (힌트: "언제 누가 좋아요를 눌렀는지" 같은 추가 정보를 어디에 적을 수 있을까요?)

✅ 예시 답안정답 보기

과제와 생각해볼 주제의 예시답안입니다. 오늘 과제는 SQL 을 짜는 게 아니라 종이 위에 직접 설계하고 판단하는 데 초점이 있고, 생각해볼 주제는 자격증·실무 양쪽 관점을 함께 담았어요. 정답을 맞히는 것보다 "왜 그렇게 그렸는지"를 설명할 수 있는지가 핵심이라, 아래 예시는 여러 모범 답 중 하나일 뿐입니다.


🎯 [과제 1 예시답안] 새 엔터티 하나를 발견해서 속성 적어보기

채점 포인트

채점 포인트 확인
데이터로 관리할 가치가 있는 새 엔터티 1개를 정했는가
속성을 3~4개 적었는가
각 행을 유일하게 구분할 식별자 1개를 골랐는가

풀이 예시

정답이 하나가 아니에요. "이걸 저장해 둬야 하나?"를 통과하는 대상이면 무엇이든 새 엔터티가 됩니다. 모범 예 두 가지를 들어볼게요.

먼저 24시간 뒤 사라지는 Story 엔터티예요. 회원이 올린 짧은 사진·영상을 다뤄야 하니 관리할 가치가 충분하죠. 속성을 정리하면 이렇게 됩니다.

텍스트
   Story 엔터티
   ┌──────────────────┐
   │ * story_id       │
   │   member_id      │
   │   image_url      │
   │   created_at     │
   └──────────────────┘
   (* 표시가 식별자 — 각 행을 유일하게 구분)

story_id 가 스토리 한 건 한 건을 겹치지 않게 구분하니 식별자예요. member_id 는 "누가 올렸는지" Member 를 가리키는 속성이고요.

다른 예로 좋아요가 눌리면 뜨는 Notification 엔터티도 좋습니다. "누구에게, 어떤 종류의 알림이, 언제" 떴는지를 저장해야 알림 목록을 보여줄 수 있죠.

텍스트
   Notification 엔터티
   ┌──────────────────┐
   │ * notification_id│
   │   member_id      │
   │   type           │
   │   created_at     │
   └──────────────────┘

notification_id 가 식별자, member_id 는 알림을 받을 회원, type 은 "좋아요·댓글·팔로우" 같은 알림 종류예요.

💡 튜터의 한마디

이 과제의 핵심은 두 가지예요. 하나는 "무엇을 엔터티로 볼 것인가" — Story 든 Notification 이든, 저장하고 다뤄야 할 대상이면 엔터티가 됩니다. 다른 하나는 "여러 속성 중 무엇으로 각 행을 구분할 것인가" — 식별자 고르기죠. 정답이 여럿이니, 본인이 정한 엔터티에 식별자가 빠지지 않았는지만 확인하면 됩니다.


🎯 [과제 2 예시답안] 두 관계의 차수를 판단하고 그려보기

채점 포인트

채점 포인트 확인
(1) Member–Comment 를 1:N 으로 맞혔는가
(2) 좋아요로 이어진 Member–Post 를 M:N 으로 맞혔는가
까마귀발 기호(──<)로 그렸는가
"한쪽이 여럿을 가질 수 있나"를 양방향으로 물어 이유를 적었는가

풀이 예시

차수 판단의 비결은 "한쪽이 여러 개를 가질 수 있나?"를 양방향으로 한 번씩 물어보는 거예요. 두 관계에 그대로 대보겠습니다.

먼저 (1) Member–Comment 예요. 양방향으로 물어봅시다.

  • 한 회원이 댓글을 여러 개 달 수 있나? → 그렇죠. 여러 개.
  • 댓글 하나는 여러 회원이 함께 단 건가? → 아니에요. 한 회원이 단 거죠.

한쪽만 여럿이니 1:N 입니다.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Member  │ 1 ────────< N  │ Comment  │
   └──────────┘                └──────────┘
   한 회원(1)이 여러 댓글(N)을 단다

다음 (2) 좋아요로 이어진 Member–Post 예요. 똑같이 양방향으로요.

  • 한 회원이 여러 게시물에 좋아요를 누를 수 있나? → 그렇죠. 여러 개.
  • 게시물 하나도 여러 회원에게 좋아요를 받나? → 그렇죠. 여러 명.

양쪽 다 여럿이니 M:N 입니다.

텍스트
   ┌──────────┐                ┌──────────┐
   │  Member  │ M >──────< N   │   Post   │
   └──────────┘                └──────────┘
   회원도 여러 게시물에 좋아요,
   게시물도 여러 회원에게 좋아요  양쪽 다 여럿

까마귀발(──<)의 갈라진 쪽이 'N(여러 개)'을 가리킨다는 것, 양쪽 다 여럿이면 양쪽 모두 까마귀발이 된다는 것(>──<)까지 챙기면 완벽해요.

💡 튜터의 한마디

차수를 헷갈리는 분들은 대개 한 방향만 물어보고 멈춰요. "회원이 댓글을 여러 개 단다"까지만 보면 1:N 인지 M:N 인지 가를 수가 없죠. 반대 방향 — "댓글 하나를 여러 회원이 다나?"까지 물어봐야 비로소 1:N 인지 M:N 인지 갈립니다. 양방향으로 묻는 습관, 그게 차수 판단의 전부예요.


🎯 [과제 3 예시답안] 비정규의 문제를 자기 말로 설명하기

채점 포인트

채점 포인트 확인
한 표에 담을 때 같은 정보가 반복되는 중복을 지적했는가
닉네임 변경 시 생기는 사고 시나리오를 들었는가
그래서 표를 나눠야 한다(정규화 필요성)를 자기 말로 정리했는가

풀이 예시

팔로우는 회원과 회원의 M:N 관계예요. 이걸 표로 나누지 않고 "한 표에 회원 정보와 팔로우 관계를 다 담는다"면 어떤 일이 벌어지는지 따라가 봅시다.

한 회원이 팔로우를 맺을 때마다, 그 줄에 그 회원의 닉네임 같은 정보가 함께 들어가요. 그러니 한 회원이 50명을 팔로우하면 그 회원의 닉네임이 50번 반복돼서 저장됩니다.

텍스트
   비정규 — 한 표에 회원정보 + 팔로우 관계를 다 담기

   ┌───────────┬───────────┬──────────────┐
   │ username  │ nickname  │ following    │
   ├───────────┼───────────┼──────────────┤
   │ jaehoon   │ jaehoon_n │ minji        │
   │ jaehoon   │ jaehoon_n │ seungwoo     │  jaehoon 의 nickname 이
   │ jaehoon   │ jaehoon_n │ narae        │   팔로우마다 반복!
   └───────────┴───────────┴──────────────┘
   문제: jaehoon 이 nickname 을 바꾸면  3 줄(50명이면 50줄) 다 고쳐야 함
         한 줄이라도 빠뜨리면  같은 사람인데 닉네임이 둘로 갈라짐

여기서 jaehoon 이 닉네임을 바꾸고 싶어 한다고 해봐요. 그러면 jaehoon 이 들어간 줄을 전부 찾아 다 고쳐야 합니다. 50명을 팔로우했으면 50군데를요. 그런데 한 줄이라도 빠뜨리면, 같은 jaehoon 인데 어떤 줄은 옛 닉네임, 어떤 줄은 새 닉네임으로 갈라지는 사고가 나죠.

해결은 표를 나누는 거예요. 회원 정보는 Member 표에 한 번만 두고, 팔로우는 follower_idfollowing_id 만 담아 연결만 합니다.

텍스트
   정규화 — 표를 나눠 id 로 연결

   Member 표 (회원 정보 한 번만)        Follow 표 (연결만)
   ┌───────────┬───────────┐         ┌─────────────┬──────────────┐
   │ member_id │ nickname  │         │ follower_id │ following_id │
   ├───────────┼───────────┤         ├─────────────┼──────────────┤
   │ 1         │ jaehoon_n │         │ 1           │ 2            │
   └───────────┴───────────┘         │ 1           │ 4            │
                                     │ 1           │ 8            │
                                     └─────────────┴──────────────┘
   효과: nickname 바꾸면  Member 표 한 줄만 고치면 끝

이제 닉네임을 바꿔도 Member 표 한 줄만 고치면 끝이에요. Follow 표는 누가 누구를 팔로우하는지 연결만 갖고 있어 손댈 게 없죠. 이렇게 중복을 없애려고 표를 나누는 게 정규화예요.

💡 튜터의 한마디

핵심은 "중복은 곧 변경 사고의 씨앗"이라는 거예요. 같은 정보가 여러 줄에 흩어져 있으면, 그걸 바꾸는 순간 전부 일관되게 고쳐야 하고 한 군데만 놓쳐도 데이터가 어긋납니다. 그래서 같은 정보는 한 곳에만 두고 나머지는 연결로 잇는 것 — 그게 표를 나누는 이유예요. 정규화의 단계나 규칙은 더 뒤 모듈에서 정식으로 다루니, 오늘은 이 "중복을 없애려 나눈다"는 큰 방향만 잡아두면 충분합니다.


🤔 [생각해볼 주제 1] 개념·논리·물리를 굳이 나누는 값어치

문제 상황 요약

설계를 빨리 끝내고 싶으면 바로 물리 모델(진짜 표)로 직행하고 싶어집니다. CREATE TABLE 한 번이면 끝날 것 같은데, 굳이 개념 → 논리 → 물리로 단계를 나누는 게 번거롭게 느껴질 수 있어요. 중간에 두 단계를 두는 게 어떤 상황에서 진가를 발휘할까요?

튜터의 가이드 및 해설

단계를 나누면 크게 세 가지 이점이 생겨요.

  • 관심사 분리 — 각 단계에서 한 가지에만 집중합니다. 개념 단계에선 "회원과 게시물을 어떻게 이을까"라는 큰 그림만, 물리 단계에선 "자료형을 뭐로 할까"만 고민하죠. 처음부터 큰 그림과 세부사항을 한꺼번에 정하려 들면 머리가 뒤죽박죽이 됩니다.
  • 기술 교체 시 앞 단계 재사용 — "Oracle 로 만들려다 MySQL 로 바꾸자"가 되면, 자료형이 다른 물리 모델만 다시 그리면 돼요. "회원이 게시물을 쓴다" 같은 개념·논리 모델은 그대로 살아남죠. 한 덩어리로 만들었다면 통째로 다시 그려야 했을 거예요.
  • 역할 분담과 협업 — 개념은 기획자·분석가, 논리는 설계자, 물리는 개발자가 봅니다. 단계가 나뉘어 있으면 각자 자기 단계의 산출물로 소통할 수 있어요.

진가는 특히 두 상황에서 드러나요. 하나는 DBMS 가 바뀔 때 — 앞 단계가 통째로 살아남죠. 다른 하나는 기획이 크게 흔들릴 때 — 개념 모델 수준에서 먼저 합의를 보면, 한참 진행한 표를 갈아엎는 대형 사고를 줄일 수 있어요.

물론 단계를 나누는 데도 비용은 있어요. 산출물이 늘고 시간이 더 들죠. 그래서 규모와 상황에 맞춰 어디까지 나눌지 정하는 게 현실적인 판단이에요.

🎯 SQLD는 이렇게 나온다

모델 3계층(개념·논리·물리)의 정의와 각 단계의 산출물·관점을 묻습니다. "개념 = 특정 DB 기술 무관·큰 그림", "논리 = 테이블·컬럼·식별자 명세", "물리 = 특정 DBMS 자료형까지"를 가르는 보기가 단골이에요.

함정은 ANSI-SPARC 3층(외부·개념·내부)과 이름이 비슷해 헷갈리게 섞어 내는 보기예요. 모델 3계층은 설계가 진행되는 단계, ANSI-SPARC 는 DBMS 가 데이터를 감싸 보여주는 구조 — 별개라는 점을 기억하세요.

💡 실무에선

작은 프로젝트는 개념과 물리를 거의 한 호흡에 압축하기도 해요. 굳이 논리 모델 문서를 따로 안 만들기도 하죠. 하지만 규모가 커지고 사람이 늘면, 논리 모델 산출물이 협업과 유지보수의 기준점이 됩니다. 새 팀원이 구조를 파악할 때, 기획과 개발이 합의를 볼 때 그 문서가 공통 언어가 되거든요.


🤔 [생각해볼 주제 2] 추상화의 트레이드오프 — 무엇을 남기고 무엇을 뺄까

문제 상황 요약

모델링의 첫 번째 특징이 추상화, 즉 "핵심만 추려내기"였죠. 그런데 무엇이 핵심인지는 칼로 자르듯 분명하지 않아요. 회원 엔터티에 속성을 너무 적게 담으면 어떤 문제가, 반대로 너무 많이 담으면 어떤 문제가 생길까요? 둘 사이에서 균형을 잡는 기준이 무엇일지 생각해 봅시다.

튜터의 가이드 및 해설

양쪽 끝에 각각 다른 문제가 있어요.

너무 적게 담으면 — 정작 필요한 정보를 못 담아 기능이 막힙니다. 회원에 가입일을 안 넣어두면 "가입 30일 된 회원" 같은 걸 다룰 수가 없죠. 그러면 나중에 속성을 추가하느라 구조를 또 바꿔야 하고, 이미 데이터가 쌓인 뒤라면 그 작업이 더 까다로워집니다.

너무 많이 담으면 — 관리 부담이 늘어나요. 당장 안 쓰는 속성까지 다 채워야 하니 입력하는 쪽도 번거롭고, 안 채우면 빈칸(NULL)이 잔뜩 생깁니다. 게다가 불필요한 속성일수록 누군가 한 군데만 고치고 다른 데는 안 고쳐서 데이터가 어긋날 위험도 커지죠.

그래서 기준은 이래요. "지금 이 서비스에 정말 필요한가" + "명백히 가까운 미래까지". 이 두 잣대를 통과하는 속성만 담습니다. 회원에 아이디·닉네임·자기소개·가입일 정도는 거의 확실히 쓰니 넣지만, "좋아하는 영화 장르" 같은 건 지금 그 기능이 없다면 미루는 거죠.

핵심은 "정보가 많은 것"과 "잘 설계된 것"이 다르다는 점이에요. 속성을 많이 넣는 게 후한 설계가 아니라, 꼭 필요한 걸 정확히 고른 게 좋은 설계입니다.

🎯 SQLD는 이렇게 나온다

추상화의 의미("현실에서 핵심만 추려 단순화·명확화한다")와, 엔터티가 가질 속성을 고르는 기준을 개념 문제로 냅니다. 모델링 3대 특징(추상화·단순화·명확화)을 묻는 보기와 함께 자주 나와요. "속성은 많을수록 좋다"는 식의 단정적 보기가 오답 함정입니다.

💡 실무에선

당장 안 쓸 속성을 "혹시 나중에 쓸지 모르니까" 하고 미리 다 넣는 건 경계해요. 쓰지도 않는 컬럼이 빈칸으로 쌓이면 관리만 복잡해지거든요. 보통 "지금 필요한 것 + 명백히 가까운 미래"까지만 담고, 진짜 필요해지는 시점에 추가하는 쪽을 택합니다.


🤔 [생각해볼 주제 3] M:N 을 그대로 두지 않고 푸는 설계의 이점

문제 상황 요약

좋아요와 팔로우는 양쪽이 여럿인 M:N 관계였어요. 이런 관계를 두 엔터티가 직접 잇게 두지 않고, 중간에 표를 하나 더 두는 방식으로 설계하면 어떤 이점이 생길까요? 교안 Step 4 에서 슬쩍 던졌던 "중간에 표를 하나 더 끼운다"는 힌트를 떠올려 봅시다.

튜터의 가이드 및 해설

중간에 표를 하나 두면 세 가지가 좋아져요.

  • 관계 자체의 추가 정보를 적어둘 수 있다 — 가장 큰 이점이에요. "누가 어떤 게시물에 좋아요를 눌렀다"만이 아니라, "언제 눌렀는지(created_at)" 같은 관계에 딸린 정보를 그 표에 적을 수 있죠. 회원 표에도 게시물 표에도 넣기 애매하던 정보가, 중간 표에는 자연스럽게 들어갑니다.
  • 양쪽이 여럿인 관계를 한 줄씩 깔끔히 표현한다 — "1번 회원이 42번 게시물에 좋아요"를 한 줄로 적으면, M:N 이라는 복잡한 얽힘이 단순한 줄들의 모음으로 풀립니다.
  • 회원·게시물 정보의 중복 없이 연결만 저장한다 — 중간 표에는 누가·무엇을 가리키는 값만 두니, 회원 닉네임이나 게시물 내용을 반복해 담지 않아요. 과제 3 에서 본 중복 사고를 피하는 거죠.

정리하면, M:N 을 직접 잇는 대신 중간 표를 두는 건 "관계에도 자기만의 정보가 있을 수 있다"는 걸 담아내는 설계예요. 좋아요 시각, 팔로우한 날짜 같은 게 다 그런 정보죠.

🎯 SQLD는 이렇게 나온다

M:N 관계를 두 개의 1:N 으로 풀어내는 교차 엔터티(연관 엔터티) 개념을 묻습니다. "M:N 은 그대로 구현하지 않고 중간 엔터티로 해소한다"는 원리가 출제 포인트예요. 다만 이 풀어내는 구체적 방법과 깊은 정규화 단계는 뒤 모듈에서 다루니, 오늘은 "중간에 표를 하나 둔다"는 감각과 용어 한 줄까지만 잡아두면 됩니다.

💡 실무에선

좋아요·팔로우·해시태그처럼 양쪽이 여럿인 관계는 거의 항상 중간 표(연결 테이블)로 풉니다. M:N 을 직접 잇는 구조는 실제로 만들 수가 없어서, 중간 표는 선택이 아니라 사실상 필수예요. 그 표에 좋아요 시각 같은 정보까지 함께 담는 게 자연스러운 흐름이고요.

전체 목록 데이터베이스