카테고리 없음

Polymorphic 관계 테이블을 도입한 이유

dev-diver 2025. 4. 15. 22:39

contract, business_units, activities, activity_item은 공통적으로 product와 member를 M개 가지고 있다.

이 로직은 contract-product 를 맵핑하는 테이블, contract-member 를 맵핑하는 테이블...  이런식으로 각각 만들어줄 수도 있었겠지만, 사실상 추가 제거 로직이 정확히 일치하므로 테이블을 줄일 수 있었다.
엔티티에 products, contract등 엔티티가 추가, 제거되는 기능도 새로 구현해야했는데 이것 역시 log를 추가하고 제거하는 로직은 같았기에 여러 엔티티에서 한 테이블을 돌려 쓸 수도 있게 됐다.

여기서 선택해야했다. polymorphic 테이블을 하나 만들어서 테이블 관리를 편하게 갈것인가? 아니면 mapping table을 일일히 만들어서 조회성능을 올릴 것인가

Polymorphic의 장점과 주의점

  • 다른 엔티티여도 로직이 같으므로 코드를 재활용하기 쉽다. (코드에 엔티티의 테이블 명을 넘길 수 있게 만들면 개별 매핑 테이블도 재활용 가능할 것 같긴 하다.)
  • 엔티티 간의 맵핑 관계가 자주 바뀌는 경우 대응이 쉽다. -> 실제로 우리 서비스가 그렇다. 추후에도 다대일 관계가 만들어졌다가 사라졌다가 할 가능성이 다분하다.
  • 테이블이 하나이므로 마이그레이션, 인덱스 설정, 외래키 관리, ORM 정의가 편하다.

주의점

  • 맵핑과 관련한 추가 정보가 개별적으로 변하지 않는 경우에 써야 좋다.
    • 우선순위, 순서, 매핑상태, 유효기간, 관계의 가중치, 관계의 역할 등등
  • 데이터가 많아지면 성능이 개별 테이블에 비해 떨어질 수 있다.
    • 테이블 락, 동시성 문제가 발생할 수 있다.
  • 외래키를 걸 수 없다. (무결성에 취약할 수 있다.)
  • 테이블만 보고는 논리적 의미가 명확하지 않을 수 있다. (comment로 코드를 잘 써놔야 할 것 같다)

개별 테이블의 장 단점의 위 장단점의 역이므로 생략한다.

Polymorphic 테이블을 선택한 이유

요구사항이 일주일마다 조금씩 바뀌는 경향이 있어서 맵핑의 카디널리티도 이번 기능을 올리면서 두어번 바꼈다. 이런 경우 매핑테이블을 생성했다가 삭제하는 게 너무 번거로울 것 같아, 처음부터 polymorphic으로 만들기로 했다.

위의 주의사항에 있는 것처럼 단순 매핑 외에 추가 로직이 있을 가능성은 없어보였다. 하나 있다면 manager라는 그룹 장이 있다는 것인데, 이건 한 명 뿐이므로 각 엔티티에 직접 필드로 넣어주는 방식을 선택했다. 

아주 나중 일이지만 성능이 느려졌을 경우 테이블을 분리하는 것도 경험이 될 수 있을 것 같기도 하다.

인덱스

index는 부모 엔티티를 기준으로 자식 엔티티를 조회할 일이 많으므로, ( parent_entity_code와 parent_entity_seq )에 복합으로 잡아 줄 수 있다.

한편으로는 ( parent_entity_code, parent_entity_seq, assigned_entity_code, assigned_entity_seq ) Unique 키를 잡아서 레코드 중복을 방지할 수도 있는데, 이 경우에는 위의 index가 포함되므로 위 index를 안 잡아도 된다.