트랙은 앨범의 자식이 아니다
트랙에 album_id 컬럼을 두는 쪽이 단순하지만, 한 곡이 싱글로 나왔다가 앨범에 실리거나 몇 년 뒤 컴필레이션에 들어가는 순간 틀립니다. 실릴 때마다 중복 행이 생기고 각자의 재생 수와 좋아요를 갖게 됩니다. 디스크와 위치를 가진 연결 테이블이면 녹음 하나가 인기 하나를 갖고, 앨범은 그것이 실린 여러 자리 중 하나가 됩니다.
아티스트 프로필, 앨범 발매, 오디오 특징이 포함된 트랙 카탈로그, 사용자 및 에디토리얼 플레이리스트, 소셜 팔로우, 청취 기록, 좋아요 표시한 곡, 팟캐스트 통합, 기기 관리 및 재생 대기열을 다루는 스포티파이 스타일의 음악 스트리밍 플랫폼을 위한 종합 데이터베이스 스키마입니다.
여기서 트랙은 앨범에 속하지 않습니다. tracks 가 primary_artist_id 를 들고 독립해 있고, album_tracks 가 디스크 번호와 위치로 둘을 잇습니다. 같은 녹음이 싱글에도, 앨범에도, 컴필레이션에도 세 번 저장되지 않고 실릴 수 있는 이유입니다.
추천을 가능하게 하는 것은 track_features 입니다 — tempo, energy, danceability, valence 등이 트랙마다 한 행. 분석 작업이 한 번 쓰고 추천이 읽는 값이라, 재생할 때마다 건드리는 행에 얹혀 있을 이유가 없어서 따로 뒀습니다.
팔로우는 다형 테이블 하나가 아니라 follows_artists 와 follows_playlists 둘입니다. 가리키는 대상이 다르고 읽는 화면이 다르며 서로를 알 필요가 없어서, 합쳐 봐야 타입 컬럼만 생기고 얻는 것이 없습니다.
트랙에 album_id 컬럼을 두는 쪽이 단순하지만, 한 곡이 싱글로 나왔다가 앨범에 실리거나 몇 년 뒤 컴필레이션에 들어가는 순간 틀립니다. 실릴 때마다 중복 행이 생기고 각자의 재생 수와 좋아요를 갖게 됩니다. 디스크와 위치를 가진 연결 테이블이면 녹음 하나가 인기 하나를 갖고, 앨범은 그것이 실린 여러 자리 중 하나가 됩니다.
재생 경로가 하나도 읽지 않는 숫자 컬럼 열한 개가, 모든 재생과 검색과 목록이 건드리는 행에 있을 이유가 없습니다. 나눠 두면 분석 작업이 특징 벡터를 다시 쓸 때 재생과 같은 행을 두고 경쟁하지도 않습니다.
맥락 없는 재생은 "이 곡이 들렸다" 만 알려 줍니다. 플레이리스트에서 시작됐다는 것을 아는 재생은 "그 플레이리스트가 먹힌다" 를 알려 줍니다. context_type·context_id 는 컬럼 둘로 로그를 제품 결정의 근거로 바꿉니다. 외래키가 아니라서 싸기도 합니다 — 맥락이 테이블 없는 라디오일 수도 있으니까요.
liked_songs 는 플레이리스트 행이 아닙니다. 순서가 없고 사용자 외의 주인이 없으며 공유할 수 없고, 순열이 아니라 집합으로 읽힙니다. 플레이리스트로 모델링하면 모든 플레이리스트 질의가 "진짜 플레이리스트가 아닌 하나" 를 예외 처리해야 합니다.