[데이터베이스] 데이터 정규화
데이터 정규화란 DB 설계에서 중복을 최소화하고 일관성을 유지하기 위한 과정을 의미한다.
데이터 정규화를 통해 데이터 중복이나 종속 관계의 불일치로 인해 발생하는 이상 현상을 방지할 수 있다.
데이터 정규화에는 크게 3가지 단계가 있는데, 제 1정규화, 제 2정규화, 그리고 제 3정규화가 있다.
제 1 정규화
정규화에 대한 설명을 찾아보았지만 빡통이라 직관적으로 이해하는 것이 힘들었다.
필자가 제 1정규화에 대해 이해한 핵심은 하나의 컬럼에는 하나의 데이터만 담는 것이다.
이에 대한 좋은 예시로 필자가 자주 보는 코딩애플형님의 영상이 있으니 시간나면 한번 씩 봐보길 권한다.
그렇다면 제1정규화를 왜 해야하는 걸까?
위에 예시를 기준으로 설명하면 나중에 DB에서 데이터를 찾고 싶을때, '골프 초급'을 신청한 사람의 데이터를 가져올때 쿼리문이 좀 더 길어지고 귀찮아질 수 있다는 것이다. 물론, 이로 인해 성능 저하 이슈도 있을 수 있다.
제 2 정규화
제 2정규화의 사전적인 의미는 partial dependency(부분 종속)를 제거한 테이블이다.
쉽게 말하자면, 현재 테이블의 주제와 관련성이 떨어지는 컬럼을 다른 테이블로 빼는 작업을 의미한다고도 볼 수 있다.
이를 설명하기 위해 Compositie primary key(복합 primary key)라는 개념이 있다.
우선, primary key는 알다시피 테이블내에서 각 행을 고유하게 식별하기 위한 값이다.
위 예시를 살펴보면 회원번호 103이 중복되는 것을 볼 수 있고, '김민수' 회원의 이름또한 중복되어 primary key로서의 역할을 할 수 없다는 것을 확인할 수 있다.
하지만 회원번호와 프로그램을 조합하면 primary key처럼 설정하여 각 행을 고유하게 식별할 수 있다.
이를 Composite primary key라고 부른다.
그리고 이러한 Composite primary key중 하나의 컬럼 혹은 부분적으로 종속되는 컬럼을 partial dependency를 가진다고 한다.
즉, 제 2정규화는 이러한 컬럼을 따로 분리하는 것을 의미한다.
예를 들어, 위 예시의 테이블이 회원들의 등록 현황이라고 한다면, 프로그램의 가격을 나타내는 컬럼은 해당 주제와 다소 관련성이 떨어져보인다는 것을 확인할 수 있다.
제 3 정규화
뭔가 할만큼 한거같지만 아직 제 3 정규화가 남았다...
제 2 정규화가 복합 primary key에 부분적으로 종속된 컬럼들을 분리하는 작업이었다면, 제 3정규화는 거기서 발전해 일반 컬럼에 종속된 테이블의 큰 주제와 관련성이 적은 일반 컬럼에만 종속된 컬럼을 분리하는 것을 의미한다.
다른 멋있는 말로는 모든 컬럼이 기본 키에 대해 이행적 함수 종속성을 갖지 않도록 설계한다는 것이다.
ex) A → B, B → C와 같은 꼴의 함수 종속 관계에서 A → C와 같은 이행적인 함수 종속 관계가 성립하는 것을 말한다
위 사진은 제 3정규화를 통해 강사들의 출신 대학을 다른 테이블로 분리한 제 3정규형을 만족하는 하나의 예시이다.
이러한 귀찮은 과정을 굳이 행하는 이유는 당연히 그만한 장점이 있기 때문일 것이다.
장점은 데이터의 수정이 편리해진다는 것이다.
예를 들어, 제 3정규화를 거치기 이전에는 '이상구' 강사의 출신 대학값이 변경되거나 했을때 이를 두번 수정해줘야했는데 테이블을 따로 분리함으로서 수정작업을 한번만 거쳐도 되게 되었다는 것을 확인할 수 있다.
추가로, 데이터의 중복이 줄어들어 데이터 일관성과 무결성이 유지된다는 것은 정규화의 전반적인 장점이다.
정규화는 언제나 옳은가?
여기까지 들으면 정규화는 무조건 좋은 것처럼 보인다.
하지만 이전에 현업에 계신분에게 이에 관해 질문했을때는 제 1 정규화도 안하는 경우가 많다는 이야기를 들었다.
왜냐하면 정규화를 수행하면 데이터의 중복이 줄어들어 데이터 일관성과 무결성이 유지되지만 이로 인해 조회 성능이 저하될 수 있기 때문.
반 정규화
회원 테이블 (Members)
회원번호 회원이름
101 | 강호동 |
102 | 손흥민 |
103 | 김민수 |
프로그램 테이블 (Programs)
회원번호 프로그램 가격 납부여부
101 | 스쿼시초급 | 5000 | 0 |
102 | 헬스 | 6000 | 1 |
103 | 헬스 | 6000 | 1 |
103 | 골프초급 | 8000 | 0 |
위 예시와 같은 테이블이 있다고 가정했을때, 회원이름과 프로그램 정보를 조회하려면 두 테이블을 조인해야 한다.
여기서 조인(Join)이란 두 개 이상의 테이블을 결합하여 원하는 데이터를 추출하는 SQL 연산을 의미한다.
회원이름과 프로그램 정보를 조회할려면 다음과 같은 쿼리문을 작성해야할 것이다.
SELECT Members.회원번호, Members.회원이름, Programs.프로그램, Programs.가격, Programs.납부여부
FROM Members
JOIN Programs ON Members.회원번호 = Programs.회원번호;
보다시피 단순히 데이터를 조회하는 행위치고는 쿼리문이 다소 복잡하다는 것을 확인할 수 있다.
그렇기에 조회성능이 중요한 경우 반정규화를 통해 중복된 데이터를 허용함으로서 성능을 향상시킬수도 있는 것이다.
물론 복잡한 조인을 사용하는 것보다 쿼리문이 줄어들어 데이터를 사용하는 것이 더 쉬울 수도 있다는 장점도 있다.
반 정규화를 하는 방법
회원-프로그램 테이블 (MembersPrograms)
회원번호 회원이름 프로그램 가격 납부여부
101 | 강호동 | 스쿼시초급 | 5000 | 0 |
102 | 손흥민 | 헬스 | 6000 | 1 |
103 | 김민수 | 헬스 | 6000 | 1 |
103 | 김민수 | 골프초급 | 8000 | 0 |
1. 중복 데이터 허용: 정규화된 테이블을 여러 개 생성하는 대신 중복된 데이터를 포함하는 하나의 테이블을 만든다.
2. 테이블 병합: 빈번하게 조인되는 테이블은 하나의 테이블로 합치는 것이 성능상 유리할 수 있다
SELECT 회원번호, 회원이름, 프로그램, 가격, 납부여부
FROM MembersPrograms;
보다시피 쿼리문의 길이가 많이 줄어들었고, 직관적으로 어떠한 의미인지 이해하기 쉬워졌다.
공부를 하다보며 느끼는 것이지만 결국 특정 기술이나 방법론이 항상 옳다는 것은 없는 것 같다.
언제나 상황과 맥락에 따라 기술이나 방법론을 적절히 선택하고 적용하는 것이 좋은 개발자의 자세라는 것을 오늘도 체감한다.