본문 바로가기

데이터 Story/모델링 이론

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

이력 엔터티를 설계하는 첫 번째 방법은 하나의 엔터티에서 과거와 현재(미래)의 데이터를 함께 관리하는 것입니다.

 

[그림1] 수수료율 엔터티에는 계좌의 종류에 따라, 어떤 방법으로 거래했는지에 따라 달라지는 수수료율을 관리합니다. 이 엔터티는 현재의 수수료율뿐만 아니라 과거의 수수료율도 함께 관리합니다.

 

[그림1]

 

이 경우 변경 일자를 관리하게 되는데요. [그림1]과 같이 변경일자 속성이든 입력일자•시작일자 속성이든요. 이력 엔터티 시리즈 글에서는 편의상 변경일자 속성을 일괄적으로 사용하겠습니다.

 

사실 변경일자 속성이 적절한지는 아직도 고민 중입니다. 현재 인스턴스에 대해서는 입력 일자가 과거 인스턴스에 대해서는 변경 일자가 명확한데, 합치게 되니 어떤 게 더욱 적절할지 고민입니다.

 

이 고민은 엔터티를 이렇게 사용하면 안 되는 게 아닌가 하는 고민으로 번지기도 하는데요. 어쨌든 현재는 변경일자 속성으로 사용하겠습니다.

 

참고로 종료일자 속성에 대해서는 지난번 글을 참고해 보세요.

 

선분 이력의 종료일자

 

하나의 엔터티에서 현재와 과거 데이터를 같이 관리하는 주요한 이유는 과거 데이터에 대한 사용 빈도가 높기 때문입니다. 수수료율이나 환율을 관리하는 엔터티는 과거 특정 시점의 값이 어떠했는지를 알려는 요건이 빈번하게 존재할 수 있습니다.

 

과거 데이터도 빈번하게 사용되며, 때로는 현재 데이터와 동시에 사용될 때도 있다면 하나의 엔터티에서 현재와 과거 데이터를 관리하는 것이 효율적입니다.

 

반면에 대부분 현재 데이터가 사용되고 과거 데이터는 거의 사용되지 않아 두 종류의 데이터가 같이 사용될 가능성이 없을 때는 과거와 현재 시점의 데이터를 분리하는 게 좋고요.

 

하나의 엔터티에서 현재와 과거 데이터를 관리하면 데이터 모델(ERD)을 관리하기 편한데요. 이는 큰 장점이어서 만약 양쪽 모델의 장•단점이 명확하지 않다면 모델의 변경(형상) 관리를 위해 하나의 엔터티에서 현재와 과거 데이터를 관리하는 모델을 사용하는 게 좋습니다.

 

이와 유사하게 현재와 과거 데이터가 같이 존재해도 별 이상이 없다면 하나의 엔터티에서 관리하는 것이 좋습니다. 이런 엔터티는 주로 중요도가 떨어지는 엔터티일 겁니다.

 

현재와 과거 데이터를 하나의 엔터티에서 관리하는 모델의 가장 큰 단점은 하위(자식) 엔터티를 가질 수 없어 확장성이 떨어진다는 것입니다.

 

[그림2]의 주문 엔터티는 현재와 과거 데이터를 함께 관리하는 엔터티인데요. 설명을 위해 만든 엔터티이지 일반적인 엔터티는 아닙니다.




[
주문]

#주문번호

#변경일자

배송처

100

2025-05-01

서울

 

[주문상품]

#주문번호

#변경일자

#상품코드

주문수량

100

2025-05-01

1010

1

100

2025-05-01

1020

3

100

2025-05-01

1050

2


[
그림2]

 

‘100’번 주문의 배송처는 서울이고 3개의 상품을 주문했습니다. 그런데 배송처가 서울에서 경기도로 변경되면 아래의 [주문] 릴레이션 같이 새로운 인스턴스가 생성됩니다.

 

[주문]

#주문번호

#변경일자

배송처

100

2025-05-01

서울

100

2025-05-02

경기


[
그림3]

 

그런데 위의 릴레이션처럼 관리하면 주문 상품 데이터가 이상해집니다(데이터 아노말리는 아니지만요). [그림4] 릴레이션을 보면 현재의 주문인 ‘100’번 주문의 주문 상품이 무엇인지 쉽게 알 수 없습니다.

 

[주문]

#주문번호

#변경일자

배송처

100

2025-05-01

서울

100

2025-05-02

경기

 

[주문상품]

#주문번호

#변경일자

#상품코드

주문수량

100

2025-05-01

1010

1

100

2025-05-01

1020

3

100

2025-05-01

1050

2


[
그림4]

 

[주문] 엔터티에는 현재의 주문 데이터가 2025 5 2일 발생한 데이터인데, [주문상품] 엔터티에는 여전히 2025 5 1일 발생한 데이터로 남아 있어 연관 관계가 끊어졌습니다.

 

사실 [주문] 릴레이션에서 최초 주문을 찾으면 해당하는 [주문상품] 릴레이션을 찾을 수 있어 연관 관계가 아주 끊어진 것은 아니지만, 희미하게 남아 있는 것이라 조회하기 불편합니다.

 

따라서 [그림5]와 같이 [주문상품] 릴레이션도 변경시켜 주어야 합니다. [주문상품1] 릴레이션은 [주문] 릴레이션의 최신 인스턴스에 해당하는 변경일자 값으로 업데이트한 것이고 [주문상품2] 릴레이션은 기존의 인스턴스는 그대로 두고 새로운 인스턴스를 생성한 것입니다.

 

[주문상품1]

#주문번호

#변경일자

#상품코드

주문수량

100

2025-05-02

1010

1

100

2025-05-02

1020

3

100

2025-05-02

1050

2

 

[주문상품2]

#주문번호

#변경일자

#상품코드

주문수량

100

2025-05-01

1010

1

100

2025-05-01

1020

3

100

2025-05-01

1050

2

100

2025-05-02

1010

1

100

2025-05-02

1020

3

100

2025-05-02

1050

2

 

[그림5]

 

실전에서 주로 [주문상품1] 릴레이션처럼 사용되지만, 하나를 선택해야 하는 상황이라면 [주문상품2]가 더 좋을 거 같고요. 주문 상품의 이력 데이터도 고려해서요. 물론 두 가지 모두 결코 좋은 방법은 아닙니다.

 

주문상품 엔터티 같은 하위(자식) 엔터티가 소수일 때는 그나마 관리할 수 있을지 모르지만 하위 엔터티는 어떻게 늘어날지 모르므로 기본적으로 관리가 안 되는 방법입니다.

 

따라서 하위(자식) 엔터티가 하나라도 존재할 때는 하나의 엔터티에서 변경 데이터를 같이 관리하는 것을 피해야 합니다.

 

실무에서 비교적 자주 볼 수 있는데요. 만약 하위 엔터티의 데이터를 전부 쫓아가서 업데이트하거나 인서트해야 하는 상황이라면 일단 모델이 잘못됐다고 생각하면 됩니다. 여러 편법도 있는데 해석을 한번 거쳐야 되는 모호한 모델도 잘못됐다고 생각하면 됩니다.

 

그밖의 특징을 보면요. 하나의 엔터티에서 현재와 과거 데이터를 관리하는 방법은 인스턴스 단위로 변경 관리하므로 변경된 속성만을 찾을 수가 없는 것이 단점입니다. 반면에 해당 인스턴스의 전체 속성을 조회할 때는 효율적이고요.

 

또한 변경되지 않은 전체 속성까지 스냅샷 상태로 보관하므로 변경된 속성 단위로 관리하는 방법보다 많은 중복 데이터가 발생해 용량을 많이 차지하고요.

 

데이터가 하나의 엔터티에 집중돼 조회 또한 집중적으로 발생한다는 점도 고려해야 합니다.

 

그리고 현재와 과거 데이터가 한 엔터티에서 관리되면 엔터티의 성격이 불명확해지는 경향이 있습니다. 내역과 이력을 같이 관리하기 때문인데요. 이는 어떤 면에서는 가장 커다란 단점일 수 있습니다.

 

원천 엔터티를 명확히 하는 것이 우선입니다. 이게 깨지면 다 소용 없게 되죠. ㅎㅎ

 

핵심적인 실체•행위 엔터티는 하나의 엔터티에서 현재와 과거 데이터를 관리하는 방법이 대개 바람직하지 않습니다.

 

마지막으로 [그림1]과 같이 하나의 엔터티에서 과거와 현재 데이터를 관리할 때는 엔터티명에 ‘~이력’을 사용하지 않는 것이 일반적입니다. 다음에 설명할, 과거 데이터를 별도로 관리할 때만 엔터티명에 ‘~이력’을 붙입니다.