본문 바로가기
  • 1+1=3
독서/개발관련

[데이터베이스 첫걸음] 8장: 정규화

by 여스 2022. 1. 9.
반응형

정규형

테이블은 한마디로 정리하면 '고유한 기본키를 가진 공통점에 의해 정리된 것들의 집합'이다. 여기서 더 나아가 어떤 열을 가져야 하는지 고려해보자.

테이블은 세상의 모든 것들을 다 자의적으로 담을 수 있고, 따라서 매우 자의적으로 열을 정의할 수도 있음. 이러면 설계자 이외에 아무도 이해를 할 수 없게 된다. 따라서 정규형이 등장. 하나의 규칙같은 것임.

 

정규형은 매우 복잡해서 1~5형이 있지만, 실무에서는 3형까지만 이해하면 된다.

정규형은 말그대로 '제대로 된 형태'를 말함. 즉 '데이터의 갱신이 발생한 경우에도 부정합이 발생하기 어려운 테이블의 형태'라는 뜻이다. 근데 1형은 너무나 당연한 것이기에 2,3형만 알면 된다.

 

제 1정규형

당연한것임. '테이블 셀에 복합적인 값을 포함하지 않는다'이다. 복합적인 값이란 '배열'을 말함. 한 열의 칸안에 {a,b,c}이런식으로 여러개 넣으면 안된다.

아래처럼 하면 안돼!

사원ID(PK) 이름 나이 성별 피부양자
S001 김미경 38 박초롱
S002 박유안 30 박안나
S003 이관식 62 (이수빈,이수인)

 

테이블을 "사원 테이블", "사원-부양자"테이블 따로 나눠서 어느쪽의 셀 하나에 데이터 하나씩을 관리하도록 해야 한다. 이런 것을 '단일값'이라 하고, '스칼라 값'이라고도 한다.

 

그런데 또 다음처럼 만들고 이것도 제1정규형 만족하는데~?라고 우길수도 있음.

사원ID(PK) 이름 나이 성별 피부양자1 피부양자2
S001 김미경 38 박초롱 NULL
S002 박유안 30 박안나 NULL
S003 이관식 62 이수빈 이수인

언뜻 보면 맞으나, 나중에 피부양자가 3명,4명,5명..있는 사원이 생기면 문제가 발생함. 테이블 정의를 도중에 변경하는 것은 앱에 대한 영향이 매우 크기 때문에 나중에 정의를 변경할 위험이 있는 설계는 바람직하지 않다. 또한, 이런 기술적 관점뿐 아니라 테이블에서는 '사원'과 '피부양자'라는 두 집합을 동시에 관리한다는 것도 의미를 알기 어려운 구조이다.

 

  • 오키 알겠어. 근데 왜 '복합적인 값'을 한 셀에 넣으면 안되는데?

복합적인 값을 허용하면 기본키가 있는 행의 값을 고유하게 특정할 수 없기 때문이다. 이는 단적으로 기본키의 정의에 반한다. 

그리고 이는 곧 살펴볼 제 2정규형과 3정규형에서도 이어진다. '기본키를 특정하면 어떤 레코드의 열 값 전체가 고유하게 특정된다'라는 것은 바꿔말하면 '기본키와 그 외의 열 사이에는 함수적인 관계가 있다'라는 뜻이다.

즉, 입력값 x를 넣으면 단 하나의 출력값 y가 출력되야 하듯이, 위 표에서 김미경씨의 이름을 알고자 하면, 사원id ->이름 이라는 관계로 함수 종속성이 성립된다(기본키와 다른 열 사이에 합수적인 유일성이 성립한다). 마찬가지로 김미경씨의 나이도 사원id -> 나이 관계로 표현된다. 그러나, 김미경씨의 피부양자는 사원id ->피부양자가 성립되지 않는다. 출력값이 두명이상이니까.

 

앞으로 볼 2정규형과 3정규형도 결국 이 함수 종속성을 정리해가는 과정이다.

제 2정규형

1정규형을 만족하였지만, 2정규형을 만족하지 못한 테이블은 아래처럼 생겼음.

고객기업ID 주문번호 주문접수일 고객기업명 고객기업 규모
CA 1 2020/12/12 A상사 대규모
CA 2 2020/12/13 A상사 대규모
CA 1 ... B건설 중규모
CA 2 ... B건설 중규모
CB 3 ... B건설 중규모
CB 1 ... C화학 소규모

기본키는 고객기업ID,주문번호의 조합이다. 이 조합으로 행을 유일하게 특정하는게 가능해짐. 이 2개의 열을 조합해야만 고유한 키가 생기는 것임.

전체 테이블 셀을 보면 다 스칼라값이니까 의심의 여지없이 제 1정규형 충족한다.

그러나 2정규형은 아님. why?

이 테이블에는 '부분함수 종속성'이 존재하기 때문임. 부분함수 종속성이란, 간단히 말하면 '기본키를 구성하는 열의 일부에만 함수 종속이 존재하는 것'이다. 

다시 복습, 함수 종속이란? 

고객기업id -> 고객기업명

고객기업id -> 고객규모

이렇게 기업의 이름은 기업id만 알면 알 수 있다. 기업의 규모도 기업의 id만 알면 알 수 있어. 이 두 열에 한정해보면 {주문번호}는 쓸데없는 정보일 뿐이다. 주문번호가지고 어떤 기업에서 주문한건지 전혀 모름.

 

위처럼 부분함수 종속이 존재할 경우 해당 키와 종속하는 열만 다른 테이블로 만들어 외부로 꺼내야 한다.

->이렇게

고객기업ID 주문번호 주문접수일
CA 1 날짜..
CA 2 ....
CB 1 ...
CB 2 ...
CB 3 ...
CC 1 ...
고객기업ID 고객기업명 고객기업규모
CA A상사 대규모
CB B건설 중규모
CC C화학 소규모

위처럼 나누면 두 테이블 모두 제2정규형을 충족함.

이유: 전체 열이 기본키만으로도 함수종속성을 가지고 있으며 기본키의 일부에만 종속하는 열이 없다. 또한, '테이블은 집합이다'라는 관점에서 보면, 나눈 후의 고객기업 주문 테이블과 고객기업 테이블은 각각 확실하게 '주문'과 '고객'이라는 집합에 대응하고 있음을 알 수 있다. 즉, 각 행이 하나의 주문 또는 기업을 나타내고 있다.

 

 

제 2정규형이 왜 필요한가)

새로 거래를 하게 된 'D 출판'회사가 있다. 근데 처음하는 거래라서 이 회사의 규모를 잘 알지 못해ㅠ 그럼 당근 '고객기업규모'의 열에 값을 못 넣으니까 이 열에 null을 허용하든지 or 더미값 넣든지 해야 하지만 권장되지 않음. 

또한, 같은 고객기업의 행이 복수 행으로 존재하니까 각 행마다 값을 넣을때마다 값이 달라지게 넣는 위험이 있다.

이런 갱신 시의 데이터 부정합을 '갱신이상'이라고 함. 비정규형 테이블은 이런 갱신이상의 위험이 높다. 이유는 테이블이 올바른 집합 단위에 기초를 두고 있지 않기 때문임.

반응형

제3정규형

아래 표를 보자. 아래표는 제2정규형을 만족함. (기본키 1개 열만 있음 사실은 걍 자동으로 제2정규형도 만족됨).

그러나 갱신이상이 존재함. 앞으로 유통, 식품 등의 업계도 관리하고 싶은데, 아직 거래한적이 없어서 테이블에 등록할 방법이 없다. 무조건 거래를 해야만 반영이 되는 것임.

이런 일이 발생하는 이유는 이 테이블에도 한개의 함수종속, 즉 '추이함수 종속'이 있다는 것임. 

즉, {고객기업ID} -> {업계코드} ->{업계명} 이런 2단계의 함수 종속이 존재함. 이런 2단계의 함수도 테이블을 나눠서 관리해야 한다.

고객기업ID 고객기업명 고객기업 규모 업계코드(FK)
CA A상사 대규모 1
CB B건설 중규모 2
CC C화학 소규모 3
업계코드 업계명
1 석유
2 건설
3 바이오

위처럼 나누면 아직 거래를 해본적이 없어도 업계테이블에 원하는 새로운 업계를 추가할 수 있게 된다. 

즉, 정규화 하기 전에는 '기업'과 '업계'라는 명백히 계층이 다른 집합을 하나의 테이블에서 관리하려 했었다. 이르 깔끔하게 나누어 관리하면 자연히 '제3정규형'에 도달한다.

 

'테이블은 현실세계의 개념이나 집합을 나타내는 원칙에 충실하면 테이블설계는 그렇게 어렵지 않다'

 

 

반응형

댓글