[cozy 개발일지] 프로젝트 테이블 설계
업데이트:
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 테이블은 엄청나게 커질 가능성이 높은 테이블이 된다.
- 테이블이 커지면 커질수록 그만큼 해당 유저에 대한 포인트를 조회하는데 걸리는 시간은 늘어날 것이다.
- 그리고, 하나의 테이블로 감당할 수 없을만큼 테이블이 커진다면 결국 샤딩도 생각해 봐야한다는 것.
- user가 현재 얼마의 point를 갖고 있는지 조회할 때는 아무래도 하나의 row만을 조회하는
어떤걸 선택?
(update 방식)
update lock으로 인해 발생할 수 있는 성능 문제 vs(insert 방식)
추가 aggregation 작업 및 테이블이 커질 수 있는 우려간의trade off
가 발생한다.- update 방식을 사용하면 동시성 문제가 발생될 우려가 있으며, 이를 해결하기 위한 lock이 불가피해진다.
- 그에 반해, insert 방식에서 발생할 수 있는 문제는 대처할 수 있는
여러가지 방안
들이 있다.- DB 스케일 업 (물리적 스펙업, 버전업, 더 좋은 RDB 로 교체)
- DB 스케일 아웃 (샤딩)
- INSERT, SELECT 성능이 좋은 nosql 로 교체
- 캐시 메모리 활용
- 정책으로 해결 (ex. 6개월 지난 데이터 삭제)
- 그렇기 때문에, 나는
insert 방식(user와 point 테이블간 관계를 1:n으로 설계하는 방식)을 선택
했다.
댓글남기기