sungyup's.

PostgreSQL / Database Structure Design Patterns / 3.3 "Mention" System

3.3"Mention" System

멘션(태그) 시스템 추가하기

Instagram 데이터베이스 스키마를 클론하는 프로젝트에서, posts 테이블에 인스타그램에서 제공하는 보다 세부적인 기능들을 추가해보자.

캡션과 위치 정보 추가

인스타그램의 포스트는 일반적으로 텍스트 캡션과 함께, 사진이 찍힌 위치를 위도/경도 좌표로 저장할 수 있다. 이를 위해 posts 테이블에 아래와 같이 컬럼을 추가한다:

sql
ALTER TABLE posts ADD COLUMN captions VARCHAR(40), ADD COLUMN lat REAL, ADD COLUMN lng REAL;
added captions and lat, lng
captions와 lat, lng(각각 REAL이라고 불리는 덜 정교하지만 우리 프로젝트에는 충분한 수준의 정교함을 제공하는 숫자)을 추가한 테이블 상태이다.

멘션(Mention) 기능 설계

포스트와 캡션에는 다른 유저들을 태그(멘션)할 수 있는 기능이 있다.

포스트(사진)에서 멘션하기

포스트에 사람을 태그하는 기능은 일반적으로 사진 안의 특정 위치(좌표)에 말풍선을 달고, 해당 유저의 이름을 노출하는 방식이다. 따라서 아래와 같은 정보가 필요하다:

  • 어떤 유저를
  • 어떤 포스트에서
  • 사진의 어느 위치에?

즉, user_id, post_id, x, y 좌표가 필요하다.

캡션(포스트에 적힌 글)에서 멘션하기

캡션에서 태그는 텍스트가 나오다가 중간에 "@유저명" 식으로 유저를 태그한다.

TEXT
'Thanks @sungyup for good post! Also, cheers to @snoopy, you are the best!'

하지만 그렇다고 반드시 태그를 위한 데이터베이스가 필요할까? 생각해보면, @유저명 식으로 캡션에서 태그를 하는 형식이 정해져있다면, 앱 단에서 충분히 해당 텍스트는 하이라이트하고 링크로 만들 수 있을 것이다.

캡션의 태깅에 대한 데이터베이스가 필요한지 여부는 아래의 기능들과 같이 따로 데이터베이스가 있어야만 구현이 가능한 기능들이 필요한지에 달렸다.

  • 어떤 유저가 멘션된 포스트 목록 보기
  • 가장 많이 멘션된 유저 랭킹
  • 멘션되었을 때 알림 받기

데이터베이스 설계하기

설계 방법 1: 단일 tags 테이블로 관리

포스트에 태그하는 것과 캡션에 태그하는 것은 아주 달라보이지만, 실제로 이들이 초래하는 결과는 같다. 어느 유저를 특정 포스트에서 태그했음을 알려야하고, 해당 태그 정보는 따로 관리가 되어서 정렬되는데 쓰일 수도 있어야 한다.

따라서 tags 테이블을 두 경우에 대해 별도로 만들 필요 없이, x와 y좌표 값이 있다면 포스트 태그, 아니면 캡션 태그라고 간주할 수 있다.

iduser_idpost_idxy
133352235
211NULLNULL
344574925
433472578
533NULLNULL

설계 방법 2: photo_tags, caption_tags 분리

굳이 x와 y 값이 필요하지 않은 데이터에 대해 해당 열이 있는 테이블에 저장하는 것은 불필요하다. 따라서 photo_tagscaption_tags 테이블을 각각 만드는 방법이 있다.

photo_tags 테이블:

iduser_idpost_idxy
133352235
244574925
333472578

caption_tags 테이블:

iduser_idpost_id
111
233

어떤걸로 해야할까?

두 가지의 설계가 모두 가능하다면, 어떤 기준으로 더 나은 설계를 할 수 있을까?

이럴 땐 아래와 같은 사항들을 고려해서 결정한다:

  • caption_tagsphoto_tags 테이블에 대한 쿼리 비중이 다를 것으로 예상하는지?
    • 만약 그렇다면 분리하는게 좋다. 예를 들어, photo_tagscaption_tags의 1/10 비율 정도로 쓰일 것이라고 예상된다면, 테이블 분리가 효율적이다.
  • 앞으로 이 태그들의 기능이 확장되거나 바뀔 것으로 예상하는지?
    • 예를 들어, 차후 photo_tag에 커멘트가 달릴 수 있을까? caption_tag에 뭔가 새로운 열이 필요할 가능성이 있을까?
    • 만약 기능이 바뀐다면 분리하는게 좋다. 합쳐진 상태에서 계속 열을 추가하다보면 관리가 어려워진다.

이번 예시에서는 설계 방법 2, 즉 포스트와 캡션에 대한 태그를 분리하는 디자인을 택한다.

sql
Table photo_tags { id SERIAL [pk, increment] created_at TIMESTAMP updated_at TIMESTAMP post_id INTEGER [ref: > posts.id] user_id INTEGER [ref: > users.id] x REAL y REAL } Table caption_tags { id SERIAL [pk, increment] created_at TIMESTAMP updated_at TIMESTAMP post_id INTEGER [ref: > posts.id] user_id INTEGER [ref: > users.id] }

아래는 이렇게 바꾼 diagram이다.

add tags
photo_tags와 caption_tags 두 테이블을 추가한 다이어그램.