본문 바로가기
DB/데이터모델링

데이터모델링이론 - 데이터 모델링시 정규화가 필요한 이유 (제1정규화, 제2정규화, 제3정규화, 반정규화)

by 참외롭다 2024. 1. 15.
반응형

 

데이터모델링이론 - 데이터 모델링시 정규화가 필요한 이유 (제1정규화, 제2정규화, 제3정규화, 반정규화)데이터모델링이론 - 정규화를 해야하는 이유(제1정규화, 제2정규화, 제3정규화, 반정규화)

 

성능 데이터 모델링 수행 절차

1. 데이터 모델링 시 정규화를 정확하게 수행한다.

2. 데이터베이스의 용량을 산정한다.

3. 데이터베이스에 발생되는 트랜잭션의 유형을 파악한다.

4. 데이터 베이스 용량과 트랜잭션에 유형에 따라 반정규화를 수행한다.

5. 이력모델 조정, PK/FK조정, 슈퍼타입/서브타입 조정을 수행한다.

6. 성능관점에서 데이터모델을 검중한다.

 

 

성능 데이터 모델링 고려사항

 

기본적으로 정규화는 중복 데이터를 제거함으로써 조회성능을 향상케합니다. 용량산정을 통해 트랜잭션의 유형과 용량을 저오학하게 분성해야합니다. 이력모델 조정, PK/FK조정, 슈퍼타입/서브타입 조정을 수행해야합니다. 특히 이력데이터는 시간에 따라 반복적으로 발생하기 때문에 성능을 고려해 칼럼을 추가할 수 있도록 설계해야합니다.

 

데이터 모델링에서의 정규화

 

 

데이터 모델링에서 정규화는 반드시 필요합니다. 

 

정규화

이상현상이 있는 엔터티를 분해하여 이상현상을 없애는 과정을 말합니다. 정규화를 진행하면 하나의 엔터티를 분해해 다수의 엔터티을 생성하게 됩니다. 기본적인 정규화의 목적은 테이블 간에 중복된 데이터를 허용하지 않는 데 있습니다.

중복된 데이터를 허용하지 않음으로써 데이터의 무결성(Integrity)을 유지할 수 있으며, DB의 크기 역시 줄일 수 있습니다. 이상현상에 따라 테이블을 분해하는 정규화 단계가 정의돼 있습니다.

 

제1 정규형 : 모든 속성은 반드시 하나의 값을 가져야 합니다.

 

아래는 연락처 속성에 집전화, 휴대전화 값을 구분하지 않고 입력하도록 설계된 엔터티입니다.

 

고객연락처
고객번호 고객명 연락처
10000 정우진 02-123-4566,010-1235-1234
10001 한형식 010-1234-1111
10002 황영은 02-123-4124, 010-2345-123

 

위와 같이 엔터티가 정의되면 다음과 같은 문제가 발생합니다.

 

- 집전화만 여러 대 거나 휴대전화만 여러대 인 경우 원하는 속성값을 추출하기가 어렵습니다.

 

- 명확하지 않은 속성값은 다른 유형의 데이터를 포함할 수 있어 속성 본연의 의미가 퇴색될 수 있습니다.

 

고객연락처 엔터티를 별도로 분리하고 고객 데이터와 관계를 맷는 방식으로 이 문제를 해결할 수 있습니다.

 

고객연락처
고객번호 순번 연락처
10000 1 02-123-4566
10000 2 010-1235-1234
10001 1 02-123-4124
10001 2 010-2345-123
10002 1 02-345-6789
10002 2 010-2333-4444

 

만약 집전화와 휴대폰 번호의 구분이 필요하다면 '연락처구분코드' 속성을 추가해 연락처 유형을 구분할 수 있습니다.

 

아래는 다중 값이 아닌 중복 유형의 속성을 갖는 엔터티입니다. 

 

주문
PK 주문번호
  상품번호1
상품명1
상품번호2
상품명2

 

위 엔터티모델은 다음과 같은 문제점이 있습니다.

 

- 상품을 3개 이상 주문할 수 없습니다.

 

- 인덱스에 상품 1과 상품 2 칼럼을 각각 추가해야 합니다.

 

- 상품을 추가하려면 칼럼을 계속해서 추가해야 합니다.

 

속성을 추가하기 위해 테이블을 수정하는 것은 테이블 Lock을 유발합니다. 인덱스 구성 칼럼이 많아지는 것 또한 입력, 수정 삭제 속도에 영향을 줍니다.

 

주문상품정보를 별도의 엔터티로 분리하여 기존테이블의 주문번호와 상품번호를 외래식별자로 지정함으로써 문제를 해결할 수 있습니다.

 

주문상세
FK 주문번호
상품번호
  상품명

 

더 이상 주문 상품의 수에 테이블구조가 영향을 받지 않고 추가적인 인덱스도 필요가 없습니다.

 

제2 정규형 : 엔터티의 일반속성은 주식별자 전체에 종속되야 합니다.

 

위의 주문상세 엔터티는 다른 문제가 있습니다. 상품명 속성이 주식별자인 (주문번호+상품번호)에 종속되지 않고 상품번호에 대해서만 종속적입니다. 함수의 종속성은 데이터가 어떤 기준값에 의해 종속되는 현상을 말합니다. 기준값을 결정자라 고하고 종속되는 값을 종속자라고 합니다. 상품명은 종속자이고 상품번호는 결정자입니다. 

 

 

상품번호와 상품명의 값이 중복됩니다. 상품번호는 고객이 상품을 주문할 때 발생하는 매핑정보로서의 의미가 있습니다. 상품번호는 주문번호와 함께 식별자의 의미이기 때문에 중복된다고 볼 수 없지만 상품명은 상품번호에만 종속적입니다. 이는 엔터티의 일반속성은 주식별자 전체에 종속적이어야 한다는 제2 정규형 규칙을 위배한 것입니다.

 

이런 형태의 엔터티에는 다음과 같은 문제점이 있습니다.

 

- 상품명이 변경되면 중복된 상품명을 모두 변경해야 합니다. 많이 팔린 상품일수록 변경해야 할 상품명의 수가 많이 집니다.

 

- 특정 시점에 아직 변경되지 않은 레코드가 존재하면 이때 들어온 트랜잭션은 일관되지 않은 데이터를 조회하게 됩니다.

 

결과적으로 데이터 중복은 조회성능과 데이터 정합성을 저해합니다. 상품 엔터티를 별도로 관리해 이 문제를 해결할 수 있습니다.

 

 

상품엔터티를 추가하면 주문상세 엔터티의 부분 종속성을 제거할 수 있습니다. 상품명 속성을 상품 엔터티에서 관리하고 상품번호를 매핑키로 활용해 상품명을 확인하는 구조입니다.

 

 

제3 정규형 : 엔터티의 일반속성 간에는 서로 종속적이지 않아야 합니다.

 

주문
PK 주문번호
  고객번호
고객명

 

 

위 엔터티에서 고객번호는 주문번호에 종속적이고, 고객명은 고객번호에 종속적입니다. 이를 '이행적 종속'이라 하고 이행적 종속을 배제하는 것을 '제3 정규형'이라고 합니다. 제2 정규형의 조건을 모두 만족했지만 고객명이 식별자가 아닌 일반속성에 종속적인 것은 제3 정규형 조건 위배에 해당합니다.

 

- 만약 고객명이 바뀌면 주문 엔터티의 고객명을 전부 갱신해야 합니다. 이는 주문 엔터티와는 관련이 없는 트랜잭션입니다.

 

- 고객명 중복으로 인해 성능부하 및 정합성을 저해합니다. 

 

고객 엔터티를 별도로 만들고 고객번호로 주문 테이블과 관계를 맺어 제3 정규형을 조건을 만족할 수 있습니다. 데이터 중복에 대한 문제도 개선할 수 있습니다.  

 

고객
PK 고객번호
  고객명
고객주소
고객별명

 

주문
PK 주문번호
FK 고객번호
  고객명

 

 

정규화는 필수적이지만 무조건적이지는 않습니다. 상황에 따라 반정규화를 통해 구조를 느슨하게 모델링할 수도 있습니다. 기본적으로 정규화를 진행한 이후 반정규화를 고려합니다.

 

반정규화

 

반정규화는 정규화를 반대로 하는 것으로 역정규화라고도 합니다. 정규화가 데이터의 중복을 최소화하기 위함이라면 반정규화는 성능을 위해 데이터의 중복을 허용하는 것입니다. 반정규화는 조회 성능을 향상할 수는 있지만 입력, 수정, 삭제의 성능은 저하될 수 있습니다.

 

아래의 주문 엔터티에서 주문 상태코드는 코드값으로 '주문, 취소, 반품, 교환'의 정보를 관리하고, 결제엔터티의 결제일시 속성은 실제 결제를 진행한 일시정보를 관리합니다. 결제 엔터티에서 결제수단구분코드 속성은 '카드결제, 계좌이체, 핸드폰결제'를 관리하는 코드 값입니다. 결제수단번호 속성은 결제수단구분코드에서 사용한 실제 '카드번호, 계좌번호, 핸드폰번호'를 관리합니다.

 

주문
PK 주문번호
  고객번호
주문상태코드

 

결제
PK 결제번호
FK 주문번호
  결제수단구분코드
결제수단번호
결제일시

 

-- 주문서 작성시 최근 결제 정보를 미리 세팅하여보려주려 한다. 
SELECT A.결제수단번호
FROM (
	SELECT B.결제수단번호
	FROM 주문 A, 결제 B
    WHERE A.주문번호 = B.주문번호
    AND A.고객번호 = '1234'
    AND B.결제수단구분코드 = '신용카드'
    ORDER BY B.결제일시 DESC
)
WHERE ROWNUM = 1

 

 

위의 쿼리는 고객번호가 1234인 주문 내역이 많을수록 조회 성능이 나빠집니다. 최종결과는 항상 1건이지만 주문내역이 많을수록 조인 건수가 증가합니다. 이때 결제 엔터티에 고객번호 속성을 반정규화함으로써 조인에 대한 성능 부하를 개선할 수 있습니다.

 

결제
PK 결제번호
FK 주문번호
  결제수단구분코드
결제수단번호
결제일시
고객번호

 

SQL을 다음과 같이 수정할 수 있습니다.

 

-- 주문서 작성시 최근 결제 정보를 미리 세팅하여보려주려 한다. 
SELECT A.결제수단번호
FROM (
	SELECT 결제수단번호
	FROM 결제
    WHERE 고객번호 = '1234'
    AND 결제수단구분코드 = '신용카드'
    ORDER BY 결제일시 DESC
)
WHERE ROWNUM = 1

 

위처럼 요건에 따라 반정규화를 통해 성능을 향상할 수 있지만 남용한다면 큰 문제를 야기할 수 있습니다.

 

반정규화를 적용한 모델에서 성능이 저하되는 경우

 

주문
PK 주문번호
  고객번호
주문상태코드

 

배송
PK 배송번호
FK 주문번호
  배송구분코드
송장번호
배송일시

 

위와 같이 정규화된 두 엔터티가 있습니다. 이때 성능을 위해 배송 엔터티에 주문엔터티에 송장번호를 추가하여 반정규화 할 수 있습니다.

 

주문
PK 주문번호
  고객번호
주문상태코드
송장번호

 

주문엔터티에서 송장번호를 조회할 때 배송엔터티와 조인하지 않아도 되므로 조회 성능은 향상됩니다. 하지만 문제점이 있습니다. 고객이 주문하는 시점에 바로 송장번호가 생성되지 않기 때문에 주문 레코드 생성 시 송장번호에는 NULL 이 들어가며 배송준비가 완료된 후 송장번호를 다시 갱신(UPDATE) 해야 합니다. 

 

반정규화 이후 전에 없던 갱신 프로세스가 추가 됐습니다. 이때는 반정규화와 갱신 프로세스 추가 사이에서 고민이 필요합니다. 반정규화 하지 않고 인덱스를 변경하는 대안도 있습니다. 반정규화는 판단의 근거가 명확할 때 비로소 진행히야 합니다. 

반응형