본문 바로가기
C.W.K.
Stream
Lesson 06 of 10 · published

Cardinality — 1:N과 N:N

~14 min · relationships, cardinality, junction-table

Level 0Scout
0 XP0/80 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

이 두 관계가 99%를 덮어

관계형 schema는 거의 전부 두 가지 관계 위에 세워져.

  • One-to-many — author 한 명에 post 여러 개. FK는 'many' 쪽에 붙어.
  • Many-to-many — post마다 tag가 여럿이고 tag마다 post도 여럿이야. Junction 테이블로 풀어. join table이나 link table, association table이라고도 불러.

1:1은 드물어. 대개는 두 테이블을 합치라는 신호야. 뜨거운 컬럼과 차가운 컬럼을 일부러 갈라놓은 경우만 빼고.

Principle: TEXT 컬럼에 id를 쉼표로 이어 넣고 싶어지면 거기서 멈춰. 그게 junction 테이블이 필요하다고 비명 지르는 소리야. SQL은 '이 컬럼 안에 42가 들어 있는 row 다 찾아줘'에 좋은 답을 못 줘. junction 테이블은 그 질문을 인덱스 타는 JOIN으로 바꿔주고.

Code

1:N — author + post·sql
CREATE TABLE authors (
  id INTEGER PRIMARY KEY, name TEXT NOT NULL
) STRICT;

CREATE TABLE posts (
  id INTEGER PRIMARY KEY,
  author_id INTEGER NOT NULL REFERENCES authors(id),
  title TEXT NOT NULL
) STRICT;

CREATE INDEX idx_posts_author ON posts(author_id);  -- 거의 항상 원함
N:N — post + tag, junction 테이블·sql
CREATE TABLE tags (
  id INTEGER PRIMARY KEY, name TEXT NOT NULL UNIQUE
) STRICT;

CREATE TABLE post_tags (
  post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
  tag_id  INTEGER NOT NULL REFERENCES tags(id)  ON DELETE CASCADE,
  PRIMARY KEY (post_id, tag_id)
) WITHOUT ROWID;

-- 'sql' 태그 달린 모든 post:
SELECT p.id, p.title FROM posts p
INNER JOIN post_tags pt ON pt.post_id = p.id
INNER JOIN tags t       ON t.id      = pt.tag_id
WHERE  t.name = 'sql';

External links

Exercise

N:N을 직접 디자인해봐. 유저가 post를 favorite으로 찜하는 관계야. 테이블 셋(users, posts, favorites)을 만들고 query를 네 개 써. 한 유저가 찜한 post, 한 post를 찜한 유저들, 찜을 가장 많이 받은 post 열 개, 그리고 아무것도 안 찜한 유저. 어디에 인덱스가 필요했는지 적어둬.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.