템플릿 둘러보기/유튜브 (YouTube)

유튜브 (YouTube)

사용자 계정, 크리에이터 채널, 메타데이터가 포함된 동영상 카탈로그, 플레이리스트, 스레드 방식의 댓글 시스템, 좋아요/싫어요, 구독 관리, 시청 기록, 알림, 채널 수익 창출, 광고 삽입 관리 및 커뮤니티 게시물 기능을 다루는 유튜브 스타일의 동영상 스트리밍 플랫폼용 전체 데이터베이스 스키마입니다.

PostgreSQL15개 테이블소셜
videostreamingcontentcreatorsocial
ERD Studio로 제작

이 스키마에 대하여

계정과 채널을 나눴습니다. users 는 로그인하는 주체이자 무엇을 봤는지의 주인이고, channels 는 올리는 주체입니다. 나눠 두었기에 한 계정이 채널 여러 개를 가질 수 있고, watch_history 와 likes 는 사람에게, videos 와 monetization 은 채널에 붙습니다.

특이한 것은 watch_history 입니다. 조회 로그가 아니라 — 그 숫자는 영상에 있습니다 — 시청자×영상마다 한 행이고 last_position_seconds 를 들고 있습니다. 이어보기 기능이 이것입니다. 쌓이는 것이 아니라 보는 동안 갱신되는 행입니다.

좋아요와 싫어요는 테이블 둘이나 카운터 둘이 아니라 is_like 플래그를 가진 한 테이블입니다. 사용자×영상마다 한 행이라 마음이 바뀌면 갱신, 취소하면 삭제이고, "한 사람은 한 번만" 이 코드가 아니라 유니크 제약이 됩니다.

눈여겨볼 관계

users → channels
한 계정이 채널 여럿을 가질 수 있습니다. 사람이 하는 일 — 시청·좋아요·구독 — 은 users 에, 올라가는 것은 channels 에 붙습니다.
users ↔ videos (watch_history)
시청자×영상마다 한 행이고 보는 동안 갱신됩니다. last_position_seconds 는 이어보기가, is_completed 는 추천이 읽습니다.
videos → comments → comments
parent_id 로 답글을 자기참조로 풉니다. is_pinned·is_hidden 이 댓글에 있어서, 크리에이터가 고정하거나 숨기는 것이 한 행의 갱신입니다.
channels → subscriptions
notify_all 이 사용자가 아니라 구독에 있습니다. 스무 채널을 구독하고 그중 둘만 알림받을 수 있어야 합니다.
channels → monetization
채널 행과 떼어 둡니다. 읽는 곳은 적고 쓰는 것은 정산 작업입니다. 수익 배분과 추정 수익이 모든 영상 페이지가 읽는 행에 있을 이유가 없습니다.

설계 판단

좋아요와 싫어요는 한 테이블

사용자×영상 한 행에 is_like 를 두면 (user_id, video_id) 유니크 제약이 "한 번만" 을 강제합니다. 테이블 둘이면 좋아요와 싫어요를 동시에 누르는 것을 막으려고 테이블을 넘나드는 검사가 필요하고, 카운터 둘이면 각자 어긋납니다. 의견을 바꾸는 것은 불리언 하나의 갱신입니다.

시청 기록은 사건이 아니라 위치를 담는다

조회 로그는 append-only 로 거대해지고, "어디까지 봤지" 에 답하려면 여러 행 중 마지막을 읽어야 합니다. 시청자×영상 한 행을 제자리에서 갱신하면 이어보기가 조회 한 번입니다. 대가는 세션별 기록을 잃는 것인데, 그것은 다른 기능이고 필요하면 이 테이블을 고칠 게 아니라 별도 테이블로 둡니다.

채널이 자기 카운터를 든다

모든 영상 페이지가 채널의 구독자 수를 보여 주므로 subscriber_count·video_count·view_count 를 channels 에 저장합니다. 계산하려면 페이지를 열 때마다 subscriptions 를 세야 합니다. 저장된 카운터가 늘 그렇듯 원본 테이블이 진실이고 숫자는 주기적으로 맞춰야 합니다.

영상에는 공개 플래그가 아니라 status 가 있다

업로드·처리·공개·비공개를 status 가 담습니다. 영상은 볼 수 있기 전부터 존재하기 때문입니다. published_at 을 따로 둬서 예약 공개가 상태 기계가 아니라 시각이 되고, 공개했다가 일부 공개로 돌렸다가 다시 공개해도 원래 날짜를 잃지 않습니다.

이 템플릿의 테이블

users사용자
8 cols
channels채널
13 cols
videos동영상
16 cols
categories카테고리
3 cols
tags태그
2 cols
video_tags동영상 태그 매핑
4 cols
playlists플레이리스트
8 cols
playlist_items플레이리스트 항목
5 cols
comments댓글
10 cols
likes좋아요/싫어요
5 cols
subscriptions구독
5 cols
watch_history시청 기록
7 cols
notifications알림
7 cols
monetization수익 창출 설정
7 cols
community_posts커뮤니티 게시물
8 cols

자주 묻는 것

users 와 channels 를 왜 따로 두나요?
한 사람이 채널 여럿을 운영할 수 있고, 둘을 읽는 페이지가 다르기 때문입니다. 시청 페이지는 채널의 구독자 수를, 로그인은 계정을 읽습니다. 합치면 채널을 하나 더 만들려고 계정을 하나 더 만들어야 합니다.
view_count 는 watch_history 에서 나오나요?
거기서 맞춰 볼 수는 있지만, 모든 목록이 보여 주기 때문에 영상에 저장합니다. watch_history 는 시청자마다 한 행이라 조회 수가 아니라 시청자 수를 셉니다. 반복 시청까지 세려면 이벤트 테이블이 따로 필요하고, 그건 또 다른 것입니다.
쇼츠는 어떻게 모델링하나요?
그냥 짧은 영상이면 duration_seconds 로 충분하고 피드가 그걸로 거릅니다. 고유 피드나 고유 지표, 고유 수익 규칙이 생기면 자기 테이블을 원합니다 — 다른 곳에서 릴스를 게시물과 나눈 것과 같은 논리입니다.
monetization 을 왜 따로 두나요?
정산 프로세스가 쓰고 읽는 곳은 거의 없습니다. channels 에서 빼 두면 모든 영상 페이지가 읽는 행이 좁게 유지되고, 돈에 관한 컬럼이 애플리케이션 대부분이 쓸 수 있는 테이블에 놓이지 않습니다.
추천은 어디에 저장되나요?
여기가 아닙니다. 이 스키마는 추천이 읽는 신호 — watch_history·likes·subscriptions — 를 담고, 결과는 바깥에서 계산해 캐시합니다. 주 데이터베이스의 추천 테이블은 질의되는 속도보다 빨리 낡습니다.