데이터가 재귀적 관계를 가지는 것은 흔한 일이다.

안티패턴 알아채기

순진한 트리라는 이름의 안티패턴을 어떻게 알아차리는가?

아래 생각을 한번이라도 해봤다면 안티패턴이 아닐까 고민 해봐야 합니다.

  • 트리에서 얼마나 깊은 단계까지 가야하는 거지?
  • 트리 데이터 구조의 코드는 건드리기 싫어.
  • 트리의 고아 노드를 정리하기 위한 스크립트를 주기적으로 돌려야해.

안티패턴 - 항상 부모에 의존하기

parent_id를 추가하는 것.

안티패턴의 SELECT

이 컬럼은 테이블 안의 다른 글을 참조하며 이 관계를 강제하기 위해 FK 조건을 겁니다.

하지만 이 경우 아래처럼 쿼리를 짜게 되고, 이는 2depth 이상 내려가지 못한다.

또한 노드의 COUNT를 가져오기 힘듭니다.

SELECT a.* , b.*
  FROM Parents a LEFT OUTER JOIN Child b ON b.parent_id = a.id

안티패턴의 UPDATE, DELETE

새로운 노드 추가하는 것은 쉽다. 하지만 노드를 삭제하는 것은 복잡하다.

서브트리 전체를 삭제하려면 FK 조건을 만족할 때까지 여러번 쿼리를 날려야 한다.

안티패턴의 대안

경로 열거

인접 목록의 약점은 트리 노드의 조상을 얻기 힘들다는 것이다.

경로 열거 방법에선 조상을 컬럼으로 저장해버린다.

아래의 path 컬럼이 그 예다.

이렇게 하면 경로 값이 올바르게 형성 되었는지 검증하기 어려워진다.

id path author comment
1 1/ 영미 할 수 있어!
2 1/2/ 길동 화이팅!

중첩 집합

자신의 부모를 저장하는 대신 자식을 저장한다.

아래처럼 left, right 를 사용하게 된다.

id left right author comment
1 1 3 영미 할 수 있어!
2 2 1 길동 화이팅!
3 1 3 둘리 가는거야!

클로저 테이블

계층구조를 저장하는 가장 우아하고 단순한 방법입니다.

부모, 자식 관계에 대한 경로만을 지정하는 것이 아닌, 트리의 모든 경로를 저장합니다.

트리 구조에 대한 정보를 Parent나 Child에 저장하는 것이 아닌 Path라는 테이블에 저장합니다.

아래와 같은 테이블에 노드를 추가하려면 본인을 참조하는 본인을 추가 해야합니다.

클로저 테이블의 장점

  • 클로저 테이블은 모든 조상-자손 관계를 명시적으로 저장하기 때문에 특정 노드의 모든 조상이나 자손을 빠르게 조회할 수 있습니다.
  • 부모-자식 관계뿐만 아니라 조상-자손 관계를 모두 저장하고 있으므로 특정 노드의 모든 하위 요소나 상위 요소를 쉽게 조회할 수 있습니다.
  • 새로운 노드를 삽입하거나 기존 노드를 이동할 때, 클로저 테이블은 해당 노드의 모든 조상과 자손 관계를 쉽게 갱신할 수 있습니다. 이는 일반적인 트리 구조에서 발생할 수 있는 복잡한 재귀적 갱신 작업을 단순화합니다
  • 트리 구조의 무결성을 쉽게 유지할 수 있습니다.
parent_id child_id
1 1
1 2
2 3
2 4
3 5

댓글남기기