정규화
Normalization
방법
같은 사실이 여러 군데 적히지 않도록 표를 잘게 나누고 키로 이어 두는 데이터 설계 방법입니다.
등장 배경
데이터를 표 하나에 몰아 담던 시절에는 주문 한 줄을 적을 때마다 고객 회사 이름과 주소와 담당자 이메일을 그 줄에 같이 적었습니다. 주문이 8천 건 쌓이면 같은 회사 이름이 8천 번 적혀 있는 셈이었습니다.
사고는 그 회사가 이름을 바꿀 때 터졌습니다. 8천 줄을 전부 찾아 고쳐야 하는데 한 줄이라도 빠뜨리면 같은 회사가 두 이름으로 남습니다. 그 뒤로 회사별 매출을 뽑으면 한 회사가 두 줄로 갈라져 나옵니다.
반대 방향으로도 새어 나갔습니다. 주문이 한 건도 없는 회사는 적어 둘 자리가 없었고, 마지막 주문을 취소하면 그 회사의 주소와 연락처까지 함께 사라졌습니다.
페이지덱에서도 같은 일이 있었습니다. 기업 고객 명단을 뽑아 달라는 요청을 받은 태오가 결제 테이블을 훑었더니 한 고객사가 "페이지덱 주식회사", "페이지덱(주)", "페이지덱" 세 가지 이름으로 흩어져 있었습니다. 테이블은 행과 열로 데이터를 담는 저장 단위입니다. 태오는 셋을 손으로 합쳐 넘겼지만 다음 달에는 같은 일을 다시 해야 했습니다.
정규화는 이 상황을 사후에 고치는 대신 처음부터 생기지 않게 만드는 설계입니다. 같은 사실을 두 군데 적지 않으면 두 군데가 어긋날 일도 없습니다.
사용 절차
이미 만들어 둔 표를 펼쳐 놓고 다섯 단계를 차례로 밟습니다. 앞 단계를 건너뛰면 뒤 단계의 판단이 서지 않습니다.
- 무엇을 알면 무엇이 정해지는지 적습니다. 주문 번호를 알면 주문 날짜가 정해지고, 회사 번호를 알면 회사 이름이 정해집니다. 이 목록이 나머지 단계의 재료입니다.
- 한 칸에 값 하나만 남깁니다. 태그 칸에 "문서,협업,공유" 를 쉼표로 이어 적어 왔다면 태그 하나에 한 줄씩 쓰는 별도 표로 옮깁니다. 한 칸에 값이 여러 개면 협업 태그가 붙은 문서를 찾는 일부터 글자 검색으로 흘러갑니다. 이 단계를 1정규형이라고 부릅니다.
- 기본 키 전체에 딸린 값만 그 표에 남깁니다. 기본 키는 행 하나를 고유하게 집어내는 칸입니다. 주문 번호와 상품 번호를 묶어 키로 쓰는 표라면 상품 이름은 상품 번호만 알아도 정해지므로 키의 절반에만 딸린 값입니다. 상품 표로 보냅니다. 2정규형입니다.
- 키가 아닌 칸에 딸린 칸을 떼어냅니다. 주문 표에 회사 번호와 회사 이름이 나란히 있다면 회사 이름은 주문이 아니라 회사 번호에 딸린 값입니다. 회사 표를 따로 만들어 옮깁니다. 3정규형이고, 실무에서 정규화했다고 말할 때는 대개 여기까지를 가리킵니다.
- 떼어낸 표를 외래 키로 다시 잇습니다. 외래 키는 다른 표의 행을 가리키는 칸입니다. 주문 줄에는 회사 이름 대신 회사 번호만 남고, 그 번호가 회사 표에 실제로 있는지는 데이터베이스가 검사합니다.
다섯 단계를 밟고 나면 표 개수가 늘어나 있습니다. 주문 한 줄을 화면에 띄우려고 표 네 개를 맞춰 읽어야 한다면 스키마를 다시 들여다볼 자리입니다. 스키마는 어떤 표가 있고 표마다 어떤 칸이 있는지를 적어 둔 설계도입니다.
적합한 상황과 한계
값이 자주 바뀌고 한 번 틀리면 곤란해지는 업무 데이터에 맞습니다. 회원, 계약, 결제, 재고처럼 고쳐 쓰는 표가 그렇습니다. 관계형 데이터베이스는 이렇게 쪼갠 표를 다시 맞춰 읽으라고 만들어진 계열이라, 표를 잇는 절차를 사람이 짜지 않아도 SQL 문장 하나로 끝납니다.
한계는 세 가지입니다.
- 읽기가 느려집니다. 표를 맞춰 읽는 일이 매번 붙기 때문입니다. 한 대시보드가 표 일곱 개를 맞춰 읽으면서 응답이 5초를 넘기면 쪼갠 대가를 치르는 중입니다.
- 이미 지나간 사실에는 맞지 않습니다. 주문서에 적힌 가격은 결제한 그 순간의 값이라서, 상품 표를 가리키게 해 두면 나중에 가격을 올릴 때 지난 주문서의 금액까지 같이 바뀝니다. 이런 값은 일부러 그 줄에 복사해 박아 둡니다.
- 쪼갤수록 손이 많이 듭니다. 3정규형 위로도 더 쪼개는 단계가 있지만 실무에서 쓸 일은 드뭅니다.
그래서 순서가 있습니다. 3정규형까지 맞춰 두고 시작한 다음, 느린 화면이 실제로 나타나면 그 자리에만 중복을 되돌립니다. 처음부터 중복을 허용하면 무엇이 원본인지 흐려져 되돌릴 기준이 없습니다.
실무 용례
"이 표는 3정규형까지만 맞춰 놓고 시작하죠."
지금은 중복을 허용하지 말고 표준적인 수준까지만 쪼개자는 제안입니다.
"회사 이름이 주문 표에 그대로 박혀 있네요. 회사 표로 빼고 번호로 걸죠."
같은 값이 여러 줄에 복사돼 있으니 표를 나눠 한 군데에서만 관리하자는 말입니다.
"여기는 정규화 풀고 가겠습니다. 대시보드가 5초 넘어요."
느려진 화면 때문에 의도적으로 중복을 되살리겠다는 뜻입니다.
페이지덱이 기업 고객 기능을 붙일 때 이 대화가 한 번에 몰렸습니다. 태오가 연 결제 표 하나에 회사 이름, 사업자 번호, 결제 수단, 담당자 이메일이 다 들어 있었고, 명단을 뽑을 때마다 이름이 세 갈래로 갈리던 원인이 그 표였습니다.
태오는 회사 표와 담당자 표를 떼어내고 결제 줄에는 회사 번호만 남겼습니다. 그 뒤 고객사가 사명을 바꿨을 때 수아가 고친 줄은 하나였고, 지난 주문서와 이번 달 청구서가 같은 이름으로 나갔습니다. 대신 결제 내역 화면은 표 세 개를 맞춰 읽게 되어 조금 느려졌고, 그 자리에는 인덱스를 걸었습니다. 인덱스는 책 뒤 찾아보기처럼 어디를 읽으면 되는지 미리 적어 두는 장치입니다.
흔한 오해
쪼갤수록 좋은 설계라고 읽는 경우가 가장 많습니다. 단계에 번호가 붙어 있으니 높은 번호가 더 나은 상태처럼 보이는 것도 무리가 아닙니다. 실제로는 3정규형이 대부분의 업무 데이터에서 멈추는 자리이고, 그 위는 특정한 중복이 실제로 문제를 일으킬 때만 갑니다. 번호를 목표로 삼으면 표만 스물몇 개로 불어나고, 정작 데이터가 어긋나는 사고는 줄지 않습니다.
저장 공간을 아끼려는 기법으로 읽는 오해도 흔합니다. 같은 글자를 8천 번 적지 않으니 용량이 준다는 말은 맞지만, 디스크값이 싸진 지금 그 이득은 결정을 바꿀 만한 크기가 아닙니다. 남는 이유는 정확성입니다. 이 점을 놓치면 "용량 여유 있으니 정규화 안 해도 되죠" 같은 판단이 나오고, 반년 뒤 같은 회사가 세 이름으로 갈린 표를 손으로 합치게 됩니다.
자주 헷갈리는 용어
| 용어 | 무엇을 하는가 | 정규화와의 차이 |
|---|---|---|
| 비정규화 | 속도를 위해 일부러 중복을 허용 | 방향이 반대입니다. 정규화로 쪼갠 뒤 느린 자리에만 되돌리는 순서로 씁니다 |
같이 보면 좋은 페이지
마지막 업데이트 2026-09-16