[cozy 개발일지] 프로젝트 테이블 설계

1 분 소요

업데이트:


Intro

  • 개발에 앞서 1차스펙에 대한 테이블간의 관계를 설계하는 시간을 가졌고, 내가 초기에 설계한 테이블간의 관계는 다음과 같았다.


테이블 설계 초안


user, point 테이블 관계에서의 고민

update 방식

  • user 테이블과 point 테이블을 처음에는 1:1로 설계했었다.
    • 각 user마다 하나의 point 테이블의 row를 갖는 방식인 것이다.
    • 즉, point 변경 때마다 해당 row를 update 하는 방식.
  • 그런데, 이렇게 설계하면 어떤 문제가 있을까?
  • 만약, 내 서비스의 유저 수가 1000만 이라고 가정해보자.
  • 그리고 추석을 맞아 모든 유저의 적립금에 1000 point씩 추가해주는 이벤트를 한다고 가정해보자.
  • 이렇게 되면 동시성 이슈를 해결하기 위해 1000만 로우에 대한 update lock을 걸어야 할 것이고(DB의 for update와 같은 쿼리 문법으로), user 로우에 접근하는 다른 작업에도 치명적인 영향을 줄 우려가 있다.

insert 방식

  • update lock 문제는 user 테이블과 point 테이블을 1:n 으로 설계하면 해결할 수 있다.
    • point 테이블에 point가 증가/감소 하는 상태 컬럼을 하나 추가해야 한다.
    • 즉, point 증가/감소 시마다 새로운 row를 insert 하는 방식.
      • 이 경우, 동시성 문제를 우려하지 않아도 된다.
  • 그렇다면 user 테이블과 point 테이블을 1:n 관계로 설계하면 모든 것이 완벽할까?
    • user가 현재 얼마의 point를 갖고 있는지 조회할 때는 아무래도 하나의 row만을 조회하는 update 방식이 유리할 것이다.
    • 왜냐하면, insert 방식에서 현재 user의 point를 조회하려면 한 유저에 해당하는 모든 point 들을 aggregation하는 추가적인 작업이 필요하기 때문이다.
      • 이 경우 방법도 db에서 직접 aggregation할 것인지, application내에 해당 데이터들을 모두 가져와 계산할 것인지에 대한 추가적인 고민도 필요하다.
    • 그리고 1000만명의 유저를 갖고 있다고 할때, point 테이블은 엄청나게 커질 가능성이 높은 테이블이 된다.
      • 테이블이 커지면 커질수록 그만큼 해당 유저에 대한 포인트를 조회하는데 걸리는 시간은 늘어날 것이다.
      • 그리고, 하나의 테이블로 감당할 수 없을만큼 테이블이 커진다면 결국 샤딩도 생각해 봐야한다는 것.

어떤걸 선택?

  • (update 방식) update lock으로 인해 발생할 수 있는 성능 문제 vs (insert 방식) 추가 aggregation 작업 및 테이블이 커질 수 있는 우려간의 trade off가 발생한다.
  • update 방식을 사용하면 동시성 문제가 발생될 우려가 있으며, 이를 해결하기 위한 lock이 불가피해진다.
  • 그에 반해, insert 방식에서 발생할 수 있는 문제는 대처할 수 있는 여러가지 방안들이 있다.
    • DB 스케일 업 (물리적 스펙업, 버전업, 더 좋은 RDB 로 교체)
    • DB 스케일 아웃 (샤딩)
    • INSERT, SELECT 성능이 좋은 nosql 로 교체
    • 캐시 메모리 활용
    • 정책으로 해결 (ex. 6개월 지난 데이터 삭제)
  • 그렇기 때문에, 나는 insert 방식(user와 point 테이블간 관계를 1:n으로 설계하는 방식)을 선택했다.


테이블 설계 최종

댓글남기기