일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- jpa
- MySQL
- 동시성 문제
- iterator
- 자바
- text
- Varchar
- java
- db
- MVCC
- Atomic Type
- Lock
- CAS
- 동시성
- Synchronized
- Di
- reflection
- Locking Read
- gc
- 백엔드
- 가비지 컬렉터
- 데이터 타입
- 가비지 컬렉션
- foreach
- 스프링
- iterable
- Today
- Total
과정을 즐기자
RDB는 정말 유연한 설계에 대응하는 것이 어려울까? 본문
대학교 내 단체 모임 생성/참여 서비스 프로젝트를 진행하면서 영속적인 데이터를 RDB에 저장하기 위해 테이블 설계를 해보았습니다.
회원 정보, 학과 정보, 학교 정보, 클랜 정보(동아리 같은 그룹), 어셈블 정보(모임) 등의 테이블이 존재합니다.
이때 유연한 설계가 필요한 요구 사항을 마주하게 되었는데 이번 글에서는 RDB로 어떻게 풀었는 지에 대한 글을 작성해보려고 합니다.
📚 어려웠던 주요 요구 사항
테이블 설계하면서 설계하기 어려웠던 요구 사항은 크게 2가지가 있었습니다.
1. 커스텀 필터 기능
2. 어셈블 (모임 정보) 통합 관리 기능
이제부터 하나씩 살펴 보겠습니다.
📘 커스텀 필터 기능
문제 상황
저희 서비스에서는 관리자가 어셈블(모임 정보)을 쉽게 관리할 수 있도록 하기 위해 참여한 회원을 학번, 생년월일, 성별 순으로 정렬하는
기능을 제공합니다. 이 기능은 회원 테이블에 이미 존재하는 데이터이므로 인덱스 설정을 해주고 가져오기만 하면 되었습니다.
하지만 문제는 회원 테이블에 존재하지 않는 데이터였습니다. 어셈블 관리를 쉽게 할 수 있도록 하기 위해 어셈블 관리자가
회원 정보를 필터링하는 정보를 추가할 수 있습니다. 예를들면 출석 체크, 송금 체크 등 필요한 필터링을 직접 작성하여 추가할 수 있습니다.
주고 받은 의견
팀원들과 이야기하여 여러 의견들이 나왔습니다.
1. RDB에 미리 컬럼을 추가하지 않는 이상 대응하기 어려울 것 같다.
2. 그냥 하나의 컬럼에 json 형식으로 데이터를 넣고 파싱을 하자.
3. NoSQL 같은 자유로운 형식의 DB가 필요할 것 같다.
하지만 RDB에 json 형식으로 저장하는 방식은 RDB를 사용하는 이유를 없애는 것이라고 생각했고 NoSQL을 사용하는 것은 대용량의
데이터를 다루는 것이 아니기 때문에 오버 엔지니어링이 될 수도 있다고 판단했습니다.
요구 사항 다시보기
커스텀 필터 기능의 요구 사항에는 출석 체크, 송금 체크 기능과 같은 커스텀 필터 기능을 추가할 수 있는 것이었는데
해당 필터들은 대부분 체크 기능일 것이라고 생각했습니다. 따라서 단순 true, false 로 판단할 수 있었기 때문에
다른 필터링처럼 인덱스를 추가하여 정렬이 필요하지는 않다고 생각하여 조금 더 쉽게 해결할 수 있을 것이라고 판단했습니다.
물론 정렬이 필요하다면 할 수 있고 중복도가 높았기 때문에 굳이 인덱스를 설정할 필요는 없었습니다.
문제 해결
문제를 해결하기 위해 2가지 테이블을 추가하였습니다.
예를들어 어셈블 관리자가 '출석 체크'라는 새로운 필터를 추가하면 custom_filter 테이블에 해당 assemble_id 에
custom_filter_name에 '출석 체크' 라는 로우가 추가 됩니다.
다음에 이렇게 생성된 로우에 custom_filter_id를 이용하여 custom_filter_status 테이블에 해당 어셈블에 있는
모든 회원의 filter_status 정보를 false 로 설정하여 데이터를 넣습니다.
이후에 어셈블 관리자가 특정 회원에 출석 상태를 변경하면 filter_status 값이 true로 변경되는 방식으로
문제를 해결하였습니다.
더 나아가서
만약 단순 해당 필터링 기능이 true, false 가 아니라면 해당 컬럼에 인덱스를 적용하고 회원에게 정보를 받는 식으로
문제를 풀어나갈 수도 있을 것 같습니다.
📗 어셈블 (모임 정보) 통합 관리 기능
다음으로 어려웠던 요구 사항은 어셈블(모임 정보) 통합 관리 기능입니다.
문제 상황
저희 서비스의 어셈블은 생성하는 주최자의 종류가 학교 전체, 학과, 클랜(동아리와 같은 그룹) 3가지입니다.
문제는 주최자가 어디냐에 따라 어셈블의 성격이 달라진다는 것입니다.
어셈블 주최자의 종류에 따른 검색도 가능해야 하고 학과 같은 경우 여러 학과가 하나의 어셈블에도 참여할 수 있어야 합니다.
주고 받은 의견
마찬가지로 팀원들과 이야기하여 여러 의견들이 나왔습니다.
1. 하나의 어셈블 테이블로 대응할 수 있나?
2. 어셈블을 생성하는 주최자의 종류마다 거기에 맞는 하나의 어셈블 테이블을 생성하자.
3. 하나의 어셈블 테이블에 학교 id, 학과 id, 클랜 id를 다 넣자.
가능하면 하나의 어셈블 테이블만 사용하고 싶었습니다. 또한 학교 id, 학과 id, 클랜 id를 다넣고 null 값을 활용하는 것은
적절하지 못하다고 생각했습니다. 심지어 학과 id는 여러 개의 값이 필요해서 해당 요구사항을 해결할 수도 없었습니다.
요구 사항 다시보기
필요한 기능은 어셈블마다 종류를 구분할 수 있어야 하며 학과의 경우에는 여러 개의 학과가 하나의 어셈블에 대응할 수 있도록
해야 합니다. 또한 주최자의 종류가 더 추가될 수 있다는 것도 생각해야 합니다.
문제 해결
저희는 카테고리 테이블을 추가하는 방식으로 해결하였습니다.
예를들어 하나의 어셈블을 생성하는데 소프트웨어학과, 화학공학과, 전자공학과 3개의 학과가 참여할 수 있도록 하려고 한다고 할 때
어셈블을 생성하기 전에 category 테이블에 category_type 을 DEPARTMENT로 설정하고 deparment_category에
해당 category_id로 해당 학과들에 맞는 id를 선택하고 생성합니다.
이제 어셈블을 생성할 때 category_id에 방금 만든 category_id를 입력해주면 됩니다.
이렇게 함으로써 어셈블마다 종류를 구분할 수 있고 각각 성격이 다른 어셈블에도 대응할 수 있으며 category가 늘어난다고 해도
어셈블에 영향을 주지 않고 다른 종류의 category를 하나 더 생성하면 됩니다.
더 나아가서
아직 해당 테이블로 직접 운영해보진 않았지만 어셈블에 category_type을 넣어서 반정규화를 하여 검색시 조금 더 효율적으로
만들어 볼 수 있을 것 같습니다. 이 부분은 운영을 해보며 성능에 문제가 되는지를 확인해보며 수정해나가보도록 하겠습니다.
🌟 정리
이번에 유연한 설계가 필요한 요구 사항을 생각해보면서 "RDB가 적합한 것이 맞나?"라는 생각도 해보았습니다.
RDB는 엄격한 데이터 구조가 있기 때문에 데이터 무결성을 지키며 데이터 중복을 줄일 수 있는 장점이 있습니다.
하지만 반대로 엄격한 데이터 구조 때문에 "유연한 설계에는 적합하지 않나?" 라는 생각이 들었던 것입니다.
NoSQL을 사용해서 json 형식을 저장해야 한다는 생각도 들었지만 update가 자주 발생하는 작업이기 때문에 오히려 적합하지
않을 수도 있다는 생각도 들었습니다.
이번에 문제를 해결하면서 든 생각은 "유연한 설계가 필요하더라도 RDB를 이용해서 최대한 해결해보자" 입니다.
유연한 설계가 필요하더라도 조금 더 생각하긴 어려울 순 있었지만 충분히 테이블을 추가하여 해결할 수 있었습니다.
RDB로도 인덱스 설정, 반정규화, 쿼리 튜닝을 통해 충분히 조회 성능도 개선할 수 있습니다.
RDB에서 NoSQL로 전환은 정말 read, write가 많고 update 되는 로직이 적을 때나 데이터를 구조화하기 어려운 경우에
해야한다는 생각이 들었습니다.
마지막으로 당근 블로그에 있는 RDB에 Json 형식을 저장할 경우 나타날 수 있는 문제 부분을 발췌한 것으로 마무리 하겠습니다.
"일반적으로 온라인 트랜잭션(OLTP) 처리 용도의 RDBMS에서는, 가볍고 빠른 쿼리들이 매우 빈번하게 처리되는 경우가 대부분이에요.
이런 온라인 트랜잭션 처리용 DBMS 서버에서는 수십 KB이상의 데이터를 한두 개의 컬럼에 저장하고, 이를 빈번하게 접근하는 것은
상당히 큰 부하를 유발해요. 수십 수백 KB 이상의 데이터는, 높은 CPU 사용량과 느린 응답 속도 그리고 네트워크 대역폭 사용량까지
걱정해야 하는 상황이 발생할 수도 있어요. 만약 여러분이 성능에 매우 민감한 DBMS 서버를 사용하고 있다면, DBMS 서버에
저장되는 데이터는 최대한 컴팩트하게 유지하시는 것을 추천해요."
참고한 자료
'Database' 카테고리의 다른 글
MVCC 만으로 팬텀 리드를 막을 수 있을까? (0) | 2024.10.27 |
---|---|
필터링 검색 기능은 어떻게 구현되는 것일까? (feat. inverted index) (1) | 2024.10.02 |
Lock을 이용한 트랜잭션 격리와 MVCC가 나온 이유 (0) | 2023.10.02 |
RDB에서 동시성 문제는 왜 발생하며 어떻게 해결해야 하나? (0) | 2023.09.30 |
무작정 데이터 타입을 VARCHAR(16683)로 하면 안되는 이유 (0) | 2023.09.04 |