본문 바로가기

데이터 Story/모델링 이론

이력 엔터티를 설계하는 10가지 방법 – 두 번째

오랜만에 이력 관련 글을 올립니다.

 

이력 엔터티를 설계하는 방법 10개 중에서 두 번째 방법입니다.

 

현재와 과거 데이터를 두 개의 엔터티에서 별도로 관리하는 방법인데요. 현재 데이터를 관리하는 엔터티에는 현재 데이터만 존재하고요. 변경된 과거 데이터는 이력 엔터티에서 관리합니다.

 

하나의 엔터티에서 현재와 과거 데이터를 관리하는 첫 번째 방법과 달리 두 종류(현재 데이터와 과거 데이터)의 데이터가 같이 사용될 일이 별로 없을 때 사용합니다.

 

그리고 하위(자식) 엔터티가 하나라도 존재할 때 사용합니다.

 

모델은 [그림1]과 같습니다. 엔터티명을고객이력’이라고 붙인 이유는 과거의 데이터를 관리하기 때문이기도 하며 이미고객’이라는 엔터티명이 사용되었기 때문입니다.



[그림1]
 

고객이력 엔터티는 고객 엔터티의 주 식별자(고객번호)를 식별 관계로 상속받고 시작일자•종료일자, 또는 변경일자 속성을 추가합니다. 이번 시리즈 글에서는 일관되게 변경일자 속성으로 사용하겠습니다.

 

고객 엔터티 속성 중의 하나라도 변경되면 변경 당시의 데이터를 스냅샷 형태로 고객이력 엔터티에 인서트합니다. 그리고 신규 데이터는 고객 엔터티에 인서트합니다(정확히는 변경된 속성만 업데이트하게 될 것입니다).

 

이 방법은 고객이력 엔터티에 이력 데이터를 발생시키는 게 다른 방법에 비해 쉽습니다. 이력 엔터티 설계 방법 중에 이게 특히 어려워 사용이 곤란한 경우가 있습니다.

 

해당 엔터티의 하위(자식) 엔터티가 존재하고, 전체 인스턴스를 대상으로 이력을 관리하려 할 때는 이 방법을 사용할 수밖에 없습니다.

하위(자식) 엔터티가 존재하면 지난번에 설명드린 첫 번째 방법은 사용할 수 없습니다. 여러 편법이 있지만 편법일뿐입니다.

 

따라서 한 엔터티에서 이력 데이터까지 같이 관리하는 방법은 핵심적인 실체 엔터티나 행위 엔터티에서는 사용할 수 없지만 이 방법은 하위(자식) 엔터티가 많은 핵심 실체 엔터티나 행위 엔터티에서 사용할 수 있습니다.

 

모델 구조가 고정화된 첫 번째 방법보다 하위(자식) 엔터티에 영향을 안 미치므로 모델이 유연해지고요.

 

단점은 첫 번째 방법과 마찬가지로 데이터 중복이 심합니다. 데이터 저장 공간이 많이 소비되고요.

 

인스턴스 단위로 관리되므로 변경된 속성이 무엇인지 알기 어렵습니다.

 

첫 번째 방법과 비교하면 모델 형상 관리가 복잡합니다. 이미 설명드렸죠. 변경일자(또는 시작일자)만 빼고 양쪽 엔터티의 스키마가 동일해야 합니다.

 

첫 번째 방법과 비교한 단점이 또 있는데요. 현재 데이터와 과거 데이터를 동시에 조회하는 요건이 있을 때 비효율이 발생할 수 있다는 점입니다.

 

이를 해결하기 위해 [그림2]와 같이 과거 데이터를 관리하는 엔터티에 현재 데이터를 함께 관리하기도 합니다. 즉 현재 데이터가 양쪽 엔터티에 다 존재하게 되죠.


[
고객]

#고객번호

주민등록번호

고객명

100001

123456-7890120

홍길동

100002

234567-8901234

박길동

100003

345678-9012345

최길동

 

[고객이력]

#고객번호

#변경일자

주민등록번호

고객명

100001

2020-02-12

123456-7890123

홍길동

100002

2020-04-14

234567-8901234

박길동

100003

2020-05-05

345678-9012345

최길동

100001

2020-07-07

123456-7890120

홍길동

 

[그림2]

 

이런 방법은 현재와 과거 데이터를 동시에 조회하는 요건의 중요도(성능과 사용빈도)에 따라 적용할 수 있지만 원칙적으로 데이터의 중복이 심하게 발생하므로 사용을 지양해야 합니다. 단순 편이성을 위해 사용하는 것은 바람직하지 않습니다.

 

[그림3]과 같이 관리하는 게 바람직합니다.

 

[고객]

#고객번호

주민등록번호

고객명

100001

123456-7890120

홍길동

100002

234567-8901234

박길동

100003

345678-9012345

최길동

 

[고객이력]

#고객번호

#변경일자

주민등록번호

고객명

100001

2020-02-12

123456-7890123

홍길동

 

[그림3]

 

하위(자식) 엔터티가 존재하지 않으면 하나의 엔터티에서 관리하는 방법에 비해 장점이 많지 않다는 것이 제 생각입니다.

 

마지막으로 서브타입에 이 방법을 적용했을 때의 모델을 설명하겠습니다.

 

[그림4]는 슈퍼타입과 서브타입을 합친 인스턴스별로 이력 데이터를 관리하는 모델입니다. 고객 엔터티의 인스턴스와 개인고객 엔터티의 인스턴스는 논리적으로 하나이므로 데이터가 어디에서 바뀌든 전체 인스턴스를 스냅샷으로 관리하는 것입니다.

 

[그림4]

 

[그림5]는 슈퍼타입과 서브타입별로 각각의 이력 데이터를 관리하는 모델입니다. 물리적으로 개별적인 엔터티를 각각 이력 관리하는 것이죠.

 

[그림5]

 

두 가지 모델 중에 [그림4] 모델이 서브타입 개념을 반영한 것으로 생각합니다. 연결된 하나의 인스턴스에 대해 동일하게 이력 데이터를 관리해서 직관적이고 조회하기도 편할 것입니다.

 

대부분의 요건이 고객이력 엔터티와 개인고객이력 엔터티를(또는 고객이력 엔터티와 법인고객이력 엔터티를) 동시에 조회하는 것이라면요.

 

하지만 고객이력과 개인고객이력 데이터가 같이 조회되지 않고 개별적으로 변경된 값만 조회되면, 즉 대표자명이 과거에 무엇이었는지만을 아는 요건이라면 고객이력 엔터티는 조회하지 않을 것입니다.

 

이 방법이 이력 데이터를 발생시키는 것도 수월하고 저장 공간도 절약될 것입니다.

 

위의 모델과 같은 서브타입에 대한 이력 엔터티는 별로 논의되지 않는데요. 실무에서 거의 못 봤습니다. 논의하지 않아 결과적으로 [그림5]와 같이 사용되지만 심도있게 고민해야 할 경우가 있습니다.

이력 데이터에 대해 슈퍼타입과 서브타입을 합쳐서 보느냐 개별로 보느냐로 판단하면 됩니다.