0. 개요
레거시 DB를 보다 보면 이런 테이블을 자주 만난다.
“요청에 대한 모든 걸 한 테이블에 다 때려 넣은 구조”
문제는 요청 내용 + 요청 메타 정보 + 결재자 정보가 전부 이 테이블에 들어가 있었다는 점이다.
시스템을 새로 개발하면서 레거시 DB에 있는 데이터들을 일부 필요한 부분들은 정규화하여 운영하기로 결정했다
1. 정규화 이전
정규화 이전 : 모든 걸 담고 있던 REQUEST 테이블
정규화 전 테이블은 대략 이런 느낌이었다.
REQUEST
- request_id
- request_title
- request_content
- request_type
- request_status
- created_at
- requester_id
- requester_name
- requester_dept
- approver_id
- approver_name
- approver_dept
- approved_at
문제점들
- 결재자가 늘어 나게 되면, 최대 결재자수가 변경될때 컬럼을 더 늘려야 함
- 같은 맥락으로 결재자 수가 작은 요청은 null로 채워지는 컬럼이 늘어남
- 요청 내용과 결재 정보가 강하게 결합됨
- 컬럼 하나 수정할 때 영향 범위가 너무 큼
즉, 역할이 다른 데이터들이 한 테이블에 섞여 있는 상태였다.
2. 정규화 과정
테이블을 나누기로 결정한 기준
“이 데이터는 언제, 왜, 얼마나 자주 바뀌는가?”
그 기준으로 나누니 3가지로 나뉘었다.
- 요청 자체의 내용
- 요청의 상태나 메타 정보
- 결재자와 결재 이력 정보
그래서 REQUEST 테이블을 아래 3개로 분리했다.
1. 요청 내용 테이블 (REQUEST_CONTENT)
요청의 “본문”에 해당하는 정보만 분리했다.
- 요청이 생성될 때 거의 한 번만 저장
- 수정 빈도가 낮음
👉 “이 요청이 무엇에 대한 요청인가?”에만 집중한 테이블이다.
2. 요청 정보 테이블 (REQUEST_INFO)
요청의 상태, 타입, 생성 정보 같은 메타 데이터를 모았다.
이렇게 분리하니 “요청 목록 조회” 쿼리도 훨씬 깔끔해졌다.
3. 결재자 정보 테이블 (REQUEST_APPROVAL)
가장 중요한 분리 포인트는 여기였다.
이 테이블이 따로 있어야 했던 이유
- 결재자는 1명이 아닐 수도 있음
- 결재 순서, 반려 이력 등 확장 가능
- 요청 테이블이 결재 정책에 종속되지 않음
이제 결재자가 늘어나도 컬럼 추가 없이 row만 추가하면 된다.
3. 느낀점
👍 좋아진 점
- 테이블 책임이 명확해짐
- 컬럼 하나 추가/수정할 때 부담 감소
- 결재 로직 확장 가능해짐
- 쿼리 읽기가 훨씬 쉬워짐
🤔 감수한 점
- JOIN은 늘어남
- ERD는 기존보다 복잡해짐
하지만 레거시 유지보수 관점에서는 JOIN 몇 개 늘어나는 것보다 구조가 명확한 게 훨씬 낫다고 느꼈다.
요청 케이스가 여러개라서 설계 자체가 패턴화 되었는데 전체적으로 동일한 구조로 관리하니 설계도 일관적이다.
구조 설계는 위와 같았고, 이제 제일 중요한 레거시 DB에서 새로운 시스템에 데이터를 dump해서 넣을 필요가 있다.
그 과정은 다음 글에서 다뤄보겠다.
'Back-end > SQL' 카테고리의 다른 글
| [레거시 정규화] DB 인덱싱 하기 (0) | 2026.02.28 |
|---|---|
| [레거시 정규화] DB 정규화 하기2 (0) | 2026.02.07 |
| [SQL] GROUP BY 한 결과로 UPDATE 하는 법 (0) | 2021.07.27 |