상세 컨텐츠

본문 제목

관계종류 (순환관계, 추출관계, 양방향 관계, 원환관계)

기록 - 프로그래밍/Data

by wjjun 2024. 6. 12. 12:12

본문

순환관계

엔티티 한 인스턴스가 같은 엔티티의 다른 인스턴스와 관계를 가지는 관계로 자기참조 관계, 재귀 관계, 리커시브 관계라고 합니다.

순환 관계도 실전에서 주요하게 사용할 수 있습니다. 많은 사람이 순환 관계를 꺼리는 것이 맞지만 선입관만 업애면 유용하게 사용이 가능합니다.

 

순환 관계는 주로 계층 구조가 생기는 데이터를 관리하는데 사용됩니다. 순환 관계를 사용하면 계층 데이터를 간결하고 효율적으로 관리가 가능합니다. 계층 데이터에는 소속 개념이 존재합니다. 큰 조직이나 분류 아래 작은 것이 소속된 형태가 계층 데이터를 이룹니다.

 

데이터가 1, 2, 3레벨이 존재해 세 개의 엔티티로 관리하면 레벨을 세분화 할수록 엔티티 개수는 늘어날 것이며 엔티티들을 조인해 조회하기 불편할 것입니다. 

 

계층 구조 모델

본사 - 본사코드 (PK) / 본사명

부서 - 부서코드 (PK) / 부서명 / 본사코드 (FK)

팀 - 팀코드 (PK) / 팀명 / 부서코드 (FK)

 

본사 - 부서 (1:N)

부서 - 팀 (1:N)

 

이 모델은 계층 단계가 늘어나면 엔티티를 추가해야 합니다. 그리고 조직이 개편돼 중간 계층이 없어지면 관리가 모호하거나 확장성이 부족한 모델입니다.

 

간혹 계층 구조를 아래 엔티티로 관리하는 모델이 있지만 이것도 변화에 취약해 좋지 않습니다.

 

변화에 취약한 계층 구조 모델과 릴레이션

조직 - 조직번호 (PK) / 본사코드 / 부서코드 / 팀번호 / 조직명

 

위 모델에서 발주 엔티티와 같이 부서 또는 팀 엔티티와 관계가 존재하면 배타 관계가 발생하니다. 조직과 같은 핵심적인 실체 엔티티가 본사, 부서, 팀 엔티티로 분해돼 있다면 조직과 관계가 존재하는 수많은 엔티티에 배타 관계가 생길 가능성이 있어 전체적으로 복잡한 모델이 됩니다.

 

본사 - 본사코드 (PK) / 본사명

부서 - 부서코드 (PK) / 부서명 / 본사코드 (FK)

팀 - 팀코드 (PK) / 팀명 / 부서코드 (FK)

발주 - 발주번호 (PK) / 발주상품 / 발주수량 / 발주조직코드 (FK)

 

계층 구조와 배타 관계가 발생한 엔티티

본사 - 부서 (1:N)

부서 - 팀 (1:N)

 

부서 - 발주 (1:N)

팀 - 발주 (1:N)

 

이러한 배타관계가 여러개 발생하면 복잡한 모델이 된다.

배타 관계를 해소하기 위해서는 배타 관계를 발생시킨 엔티티들을 통합해야 합니다.

관계가 통합돼어 단순해지면 접근도 단순하고 성능에 도움됩니다. 관리할 부분이 줄어들면 데이터 정합성도 좋아지게 됩니다.

 

계층 구조를 순환 관계로 표현해보면

 

순환관계 모델

부서 - 부서코드 (PK) / 부서명 / 부서구분코드 / 상위부서코드 (FK)

상위 부서 - 부서

 

조직을 표현하는 엔티티명 '부서'를 사용했고 부서코드가 주 식별자가 됩니다. 계층 구조는 상위부서코드 속성으로 구현됩니다.

만약 어떤 팀이 등록되면서 상위부서코드 속성에 값이 존재하면 그 값은 부서를 의미합니다.

부서가 등록될 때 상위부서코드 속성 값은 본사를 의미합니다. 본사는 상위 부서가 존재하지 않아 업무적으로는 상위부서코드 속성은 널(NULL) 값이 돼야 합니다.

 

하지만 아래와 같이 최적의 조회 성능을 위해서는 업무적인 최상위 계층의 상위 부서를 임의의 값으로 등록해 사용합니다.

이렇게 계층 관계의 엔티티가 통합되면 계층 관계와 배타 관계가 없어진 단순한 모델이 됩니다.

 

계층 구조를 통합해 관계가 단순해진 모델

부서 - 부서코드 (PK) / 부서명 / 부서구분코드 / 상위부서코드

발주 - 발주번호 (PK) / 발주상품 / 발주수량 / 발주부서코드 (FK)

 

부서 - 상위부서 (1:N)

부서 - 발주 (1:N)

 

대부분 계층 구조를 선호하지만 계층 구조의 엔티티는 SQL 사용이 어렵고 메뉴 형태로 보여주는 요건 등에서 구현이 쉽지 않습니다.

반대로 순환 구조 모델은 SQL 사용하기도 쉽고 효율적인 모델입니다.

 

계층 구조를 이루는 엔티티 속성이 유사할 때 순환 관계를 고려해야 하며 계층을 이루는 엔터티 수가 많거나 가변적이면 순환 관계를 사용해야 합니다.

 

계층이 두 개 이상이라면 즉, 계층 구조라면 순환 관계를 우선 검토하는 것이 좋습니다.

 

추출 관계

중복을 의미하는 추출 관계가 있습니다. 중복관계라고도 합니다. 추출 속성이 관계 속성일 때는 추출 관계가 됩니다.

 

추출 속성이 관계 속성일 때는 추출 관계가 됩니다. 추출 속성은 기존에 존재하는 속성 값에서 생성시킬 수 있는 속성입니다.

다시 생성시킬 수 있어 별도 저장을 하지 않아도 되는 속성입니다. 저장해서 관리하면 오히려 데이터 정합성이 훼손될 가능성이 있어 성능 문제가 없는 한 채택하지 않는 것이 맞습니다.

 

추출 관계는 상속되는 관계 깊이를 줄이려고 사용하거나 추출 속성을 관리할 때 사용합니다. 중복 속성을 채택할 때 고려해야할 것이 데이터 정합성이듯이 추출 관계도 정합성에 문제가 발생할 가능성이 있어 항상 데이터 정합성을 고려해야 합니다.

 

추출 관계의 채택은 가능한 논리 모델링에서는 고려하지 않고 물리 모델링에서 반영하는 것이 옳습니다.

아래는 추출 속성을 관계 속성으로 관리하는 모델입니다.

 

거래내역 데이터 중 최종 거래를 계좌 엔티티에서 관리하므로 관계가 존재합니다. 계좌 엔티티에서 최종거래번호 속성을 관리하지 않아도 거래내역 엔티티에서 가장 최근 일자에 거래된 인스턴스를 찾을 수 있어 생략해도 됩니다.

 

하지만 성능 문제가 존재한다고 가정하고 추출 속성이 채택 됐고 이로 인해 추출 관계가 생겼습니다.

 

추출 속성에 의해 발생한 추출 관계

계좌 - 계좌번호 (PK) / 계좌명 / 고객번호 / 최종거래번호 (FK)

거래내역 - 거래번호 (PK) / 계좌번호 (FK) / 거래일자 / 거래금액

 

이처럼 추출 속성이 관계로 관리되면 추출 관계가 사용되며 관계가 상속되는 단계가 깊을 때 조인을 줄이려고 추출 관계가 사용됩니다.

대분류, 중분류, 소분류로 관리하는 엔티티가 있을 때 소분류 엔티티에서 특정 소분류코드의 대분류코드가 무엇인지 알려면 중분류 대분류 엔티티를 조인해야 합니다.

 

그런데 이렇게 세 개의 엔티티를 조인하는 것에 성능에 문제가 발생할 수 있어 추출 속성을 도입해도 됩니다.

소분류 엔티티와 대분류 엔티티의 관계가 존재하므로 중분류 엔티티와 조인 없이 소분류 엔티티에서 대분류코드를 바로 알 수 있습니다.

 

상속 단계를 줄이기 위한 추출 관계

 

추출관계

대분류 - 중분류 (1:N)

중분류 - 소분류 (1:N)

 

대분류 - 중분류 (1:N)

대분류 - 소분류 (1:N)

중분류 - 소분류 (1:N)

 

추출 관계를 도입하면 모델에서도 알 수 있듯이 조인을 방지해 성능에 도움을 줄 수 있습니다.

하지만 성능상 유리한 면이 있지만 간과해서는 안될 부분은 데이터 정합성 입니다.

 

추출 관계를 채택하면 참조 무결성을 생성해도 데이터 정합성에 문자가 발생할 수 있습니다.

예를들어 소분류 엔티티의 소분류 코드는 102010 중분류 코드는 121212 대분류 코드는 20000

중분류 엔티티의 중분류코드는 121212 대분류 코드는 10000 처럼 데이터 정합성이 깨질 수 있습니다.

 

추출 관계가 없다면 대분류코드 속성이 존재하지 않아서 잘못된 데이터가 존재할 수 없지만 성능을 위해 도입한 추출 관계의 값을 잘못 관리하면 데이터가 달라질 수 있습니다.

 

양 방향 관계

두 엔티티 간 서로 관계가 존재하는 관계가 양방향 관계 입니다. 상호 관계나 교차 관계인 양방향 관계는 잘 알려지지 않았지만 자주 발생합니다.

 

흔히 관계는 한쪽 엔티티에서 다른 쪽 엔티티로 발생한다고 생각해 양 방향 관계는 존재해서는 안되는 관계라고 생각합니다.

하지만 양쪽 관계가 나타내는 의미가 서로 달라 양 방향 관계는 정상적인 관계입니다.

관계는 프로세스 순서나 종속 개념만 표현하는 것이 아니기 때문에 한쪽만 생기는 것은 아닙니다.

 

대표적인 양방향 모델입니다.

사원은 소속된 지점이 있고 지점은 지점장이 존재합니다. 한쪽을 기준으로 다른 쪽이 하는 역할이 달라지므로 관계 속성과 관계명에 롤(Role) 이름을 사용해야 합니다.

 

역할이 다른 양방향 관계

사원 - 사원번호(PK) / 소속지점번호(FK)

지점 - 지점번호(PK) / 지점명 / 지점장사원번호(FK)

 

추출 관계로 인한 양방향 관계

계좌 - 계좌번호 (PK) / 계좌명 / 고객번호 / 최종거래번호 (FK)

거래내역 - 거래번호 (PK) / 계좌번호 (FK) / 거래일자 / 거래금액

 

어떤 계좌가 거래를 발생했는지 관리하기 위해 거래내역 엔티티에는 당연히 계좌번호 관계 속성이 필요합니다. 그리고 계좌 엔티티에서 최종 거래를 알려면 최종거래번호 관계 속성이 필요하게돼 양 방향 관계가 됩니다.

 

양방향 관계와 유사한 관계가 원환관계 입니다.

원환관계는 엔티티 간 관계가 원형처럼 이어진 관계입니다.

 

추출 관계로 인한 원환관계

고객 - 고객번호 (PK) / 정보제공동의약정번호 (FK)

계좌 - 계좌번호 (PK) / 고객번호 (FK)

계좌약정 - 약정번호 (PK) / 계조번호 (FK) / 약정종류코드

 

고객 - 계좌 (1:N)

고객 - 계좌약정 (1:1)

계좌 - 계좌약정 (1:N)

 

계좌 엔티티의 고객번호 관계 속성과 엔티티의 계좌번호 관계 속성은 정상적인 일대다 관계입니다.

계좌약정 엔티티에서는 계좌에 약정된 항목들이 관리되는데 그중 고객의 정보를 제공해도 좋다는 약정을 체결한 데이터를 관리하는 요건으로 고객 엔티티에 정보제공동의약정번호 관계속성이 존재합니다.

정보제공동의약정번호 관계 속성은 추출 속성이므로 추출 관계입니다. 없어도 계좌약정 엔티티에서 해당 계좌번호와 약정종류를 조회하면 알 수 있습니다. 하지만 위 모델은 성능 향상 차원에서 추출 관계로 인한 원환 관계가 발생습니다.

관련글 더보기

댓글 영역