본문 바로가기
전쟁과 기술

데이터 중복은 왜 문제일까? 정규화가 필요한 진짜 이유

by 전쟁과 기술 2026. 9. 13.

주소를 한 번 바꾸었는데 어떤 화면에는 새 주소가 나오고, 다른 화면에는 예전 주소가 남아 있다면 어느 쪽을 믿어야 할까. 담당자가 한 곳을 빠뜨렸을 수도 있고, 두 시스템의 갱신 시각이 달랐을 수도 있다. 이용자에게는 단순한 불편처럼 보이지만 데이터를 관리하는 쪽에서는 꽤 까다로운 문제다.

같은 사실을 여러 곳에 적어 두면 처음에는 편하다. 주문내역을 열었을 때 고객 이름과 주소까지 한 줄에서 볼 수 있기 때문이다. 그러나 이름이나 주소가 바뀌는 순간, 편리하게 복사해 둔 값은 모두 고쳐야 할 숙제가 된다. 한 군데라도 놓치면 데이터베이스 안에 서로 다른 답이 생긴다.

앞선 글에서는 고객과 주문처럼 성격이 다른 대상을 별도의 테이블로 나누고, 기본키와 외래키로 관계를 잇는 방법을 살펴보았다. 이번에는 왜 굳이 그렇게 나누는지를 한 걸음 더 들어가 보려 한다. 정규화는 표를 복잡하게 쪼개는 기술이 아니라, 같은 사실을 가능한 한 한곳에서 책임지게 만드는 정리 원칙에 가깝다.

한줄 요약

정규화는 같은 사실의 반복을 줄이고 서로 다른 대상을 알맞게 나누어, 한 번의 변경이 한곳에서 정확하게 이루어지도록 데이터 구조를 정리하는 과정이다.

반복된 값은 복사본이 아니라 서로 다른 약속이 된다

작은 온라인 상점의 주문표를 떠올려 보자. 주문번호, 주문일, 고객 이름, 전화번호, 주소, 상품명, 가격을 한 행에 적으면 주문 한 건의 내용이 한눈에 들어온다. 주문이 열 건 정도라면 이 방식이 오히려 간단해 보인다.

문제는 단골고객이 생기면서 시작된다. 한 고객이 열 번 주문하면 이름과 연락처, 주소도 열 번 반복된다. 그 고객이 이사를 하면 열 행의 주소를 모두 바꾸어야 한다. 아홉 행만 고치면 같은 고객에게 주소가 두 개 생긴다. 어느 주소가 현재 값인지 알려면 주문일이나 수정일을 다시 따져야 한다.

이때 반복된 주소는 단순한 복사본으로 머물지 않는다. 각각이 고객의 주소를 주장하는 독립된 기록이 된다. 복사하는 순간에는 모두 같았지만 시간이 지나며 서로 다른 값으로 갈라질 가능성을 품게 된 셈이다. 데이터 중복이 저장공간보다 신뢰의 문제로 이어지는 이유가 여기에 있다.

여러 주문 기록에 같은 고객 정보가 반복되어 일부 값이 서로 달라진 데이터 관리 장면

수정할수록 틀어지는 현상을 수정 이상이라고 한다

같은 정보를 여러 행에서 고쳐야 하므로 일부만 바뀌는 문제를 수정 이상이라고 한다. 고객 주소뿐 아니라 상품 가격, 담당 부서, 장비의 설치 위치에서도 같은 일이 생긴다. 변경 대상이 많을수록 누락 가능성은 커지고, 작업 도중 다른 사용자가 데이터를 읽으면 잠시 동안 서로 다른 값이 보일 수도 있다.

이를 피하는 가장 분명한 방법은 고객의 현재 정보를 고객 테이블 한곳에 두는 것이다. 주문 테이블에는 고객번호만 남긴다. 주소가 바뀌면 고객 테이블의 한 행만 고치고, 주문 화면은 고객번호를 따라 현재 정보를 불러온다. 변경 책임이 한곳으로 모이니 무엇이 기준값인지도 분명해진다.

다만 과거 주문 당시의 배송지를 보존해야 한다면 이야기가 달라진다. 현재 고객 주소와 주문 당시 배송지는 닮아 보여도 같은 사실이 아니다. 전자는 지금의 고객 정보이고, 후자는 특정 거래가 이루어진 순간의 기록이다. 정규화는 무조건 같은 모양의 값을 하나로 합치는 일이 아니라, 각 값이 무엇을 의미하는지 구분하는 일에서 시작한다.

새 값을 넣지 못하거나 지웠더니 다른 정보까지 사라진다

한 표에 여러 대상을 뒤섞어 두면 수정할 때만 문제가 생기는 것이 아니다. 아직 주문이 없는 신규 고객을 등록하려는데 주문번호가 반드시 필요하다면 고객 정보만 먼저 넣을 수 없다. 주문표가 고객명부 역할까지 맡고 있기 때문이다. 이것을 삽입 이상이라고 부른다.

반대 상황도 있다. 어떤 상품의 마지막 주문을 취소하면서 그 행을 지웠더니 상품명과 가격, 공급처 정보까지 함께 사라질 수 있다. 주문 기록 안에 상품 정보가 붙어 있었고 별도의 상품 테이블이 없었다면 마지막 행의 삭제가 상품 자체의 삭제가 되어 버린다. 이것이 삭제 이상이다.

수정 이상, 삽입 이상, 삭제 이상이라는 이름은 다르지만 뿌리는 같다. 고객, 주문, 상품처럼 서로 독립적으로 존재할 수 있는 대상을 한 표가 함께 책임지고 있다는 점이다. 한 행을 바꾸는 일이 여러 대상에 동시에 영향을 주기 때문에 예상하지 못한 결과가 나타난다.

정규화는 표를 잘게 나누는 규칙이 아니다

정규화를 처음 접하면 제1정규형, 제2정규형, 제3정규형 같은 단계부터 눈에 들어온다. 각 단계에는 분명한 기준이 있지만, 용어만 외우면 왜 표를 나누는지 놓치기 쉽다. 먼저 기억할 것은 한 표가 무엇을 기록하는지 분명해야 한다는 점이다.

고객 테이블은 고객 한 명을, 주문 테이블은 주문 한 건을, 상품 테이블은 상품 하나를 기록한다. 고객 이름과 연락처는 고객번호에 따라 결정되고, 주문일과 주문 상태는 주문번호에 따라 결정된다. 상품 가격과 상품 분류는 상품번호에 속한다. 서로 다른 기준에 딸린 값을 알맞은 테이블로 옮기면 반복이 줄고 변경할 곳도 분명해진다.

주문 하나에 여러 상품이 들어갈 수 있으므로 주문과 상품 사이에는 주문상세 같은 중간 테이블이 필요하다. 주문상세에는 주문번호와 상품번호, 수량처럼 그 관계에서 생기는 값을 둔다. 앞선 글에서 살펴본 외래키가 나누어진 테이블을 다시 잇기 때문에, 정보를 분리하더라도 주문 전체를 재구성할 수 있다.

몇 단계까지 나누어야 하는지는 업무가 결정한다

제1정규형은 한 칸에 여러 값을 묶어 넣지 않고 하나의 값을 담도록 정리하는 데서 출발한다. 한 고객의 전화번호 여러 개를 쉼표로 이어 적어 두면 번호별 검색이나 수정이 어려워진다. 반복되는 값을 별도의 행이나 관련 테이블로 다룰 수 있어야 한다.

제2정규형과 제3정규형으로 갈수록 값이 어떤 키에 의존하는지를 따져 잘못 놓인 속성을 옮긴다. 주문상세에서 상품명이 상품번호에 의해 정해진다면 상품명은 상품 테이블이 맡는 편이 자연스럽다. 직원 테이블의 부서명과 부서 전화번호가 부서번호에 따라 정해진다면 부서 정보를 별도로 관리할 이유가 생긴다.

그렇다고 가능한 한 많은 테이블로 나누는 것이 목표는 아니다. 실제 조회 방식과 처리 속도, 변경 빈도, 이력 보존 조건을 함께 살펴야 한다. 읽는 속도를 높이기 위해 일부 값을 의도적으로 중복 저장하는 경우도 있다. 이를 비정규화라고 하지만, 실수로 생긴 중복과는 다르다. 어떤 값을 왜 복제했는지, 원본은 어디인지, 어떻게 함께 갱신할지가 정해져 있어야 한다.

장비 이름 하나가 달라도 정보체계의 판단은 달라질 수 있다

장비관리 체계에서도 중복은 비슷한 모습으로 나타난다. 장비 기본정보, 정비 이력, 장애 기록, 부품 교체내역마다 장비명과 소속부대, 설치 위치를 반복해서 적으면 당장은 각 화면을 만들기 쉽다. 하지만 장비가 이동하거나 부대 명칭이 바뀌면 여러 기록을 동시에 고쳐야 한다.

일부 기록에 예전 소속이 남아 있으면 같은 장비의 이력이 서로 다른 대상으로 집계될 수 있다. 가동률을 계산할 때 정비 이력이 빠지거나, 필요한 부품 수량이 중복으로 잡힐 수도 있다. 일반 업무에서는 보고서 수치가 어긋나는 문제로 끝날 수 있지만, 시간이 중요한 정보체계에서는 상황 판단과 자원 배분의 오류로 이어질 수 있다.

그래서 장비의 변하지 않는 식별값은 기본정보에서 관리하고, 정비와 장애 및 운용 기록은 그 식별값을 참조하게 한다. 소속이나 위치가 시간에 따라 바뀌는 이력이라면 현재 값으로 덮어쓸지, 변경 시점별 기록으로 남길지도 정해야 한다. 데이터 구조는 현실의 대상을 그대로 복사하는 그릇이 아니라, 현실의 변화를 어떤 기준으로 기억할지 정한 약속이다.

짧은 생각

현장에서 화면에 보이는 값이 이상하면 사람은 먼저 입력 실수를 의심한다. 그러나 같은 실수가 반복된다면 사람보다 구조를 살펴볼 필요가 있다. 정확한 입력을 요구하는 것만으로는, 같은 사실을 여러 번 적게 만든 설계의 약점을 오래 감출 수 없다.

정리된 데이터는 필요한 정보를 다시 묻기 쉬워진다

정규화된 데이터베이스에서는 고객, 주문, 상품이 각각의 테이블에 나뉘어 있다. 화면 하나를 만들기 위해 여러 표를 다시 연결해야 하므로 처음에는 번거로워 보일 수 있다. 하지만 각 사실이 어디에 있는지 분명하고, 기본키와 외래키가 관계를 지키기 때문에 필요한 조건에 따라 데이터를 정확히 조합할 수 있다.

이제 다음 질문이 남는다. 나뉜 테이블에서 지난달 주문만 골라내고, 고객과 상품 정보를 연결하며, 금액의 합계를 구하려면 데이터베이스에 무엇이라고 요청해야 할까. 사람이 일상어로 원하는 조건을 말하듯 데이터베이스에도 자료를 찾고 추가하고 바꾸는 공통된 표현이 필요하다.

다음 글에서는 관계형 데이터베이스와 대화하는 언어인 SQL을 살펴보려 한다. SQL 문법을 외우기보다, 데이터베이스에 질문한다는 것이 무엇인지와 SELECT가 나뉜 데이터를 어떻게 다시 꺼내 보여주는지부터 이어가겠다.