프로그래밍SQL 프로그래머

SQL에서 계층 구조(트리, 중첩된 카테고리)의 지원 및 처리를 어떻게 구현하며, 다양한 시나리오에 가장 효과적인 방법/알고리즘은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

트리 및 계층 구조 작업은 SQL 프로그래밍에서 자주 발생하는 사례입니다: 상품 카탈로그, 조직 구조, 메뉴 등. 처음에 대부분의 DBMS는 부모에 대한 참조(ParentId)만 지원했으나, 시간이 지나면서 대체 방법이 등장했습니다 — 중첩 세트 및 경로(Path), CTE를 통한 재귀 쿼리 등입니다.

문제 전통적인 Parent-Child 접근법의 나쁜 점은 큰 계층을 탐색할 때 속도가 느려진다는 것입니다; 깊이가 2-3단계를 넘는 쿼리는 JOIN의 수가 급증하게 됩니다. 더 복잡한 기술(중첩 세트, 경로 열거)은 대량의 탐색을 가속화하지만 삽입/삭제를 어렵게 만듭니다.

해결책 — 특정 문제에 맞는 최적의 저장 모델 선택:

  • 자주 변경되지 않고 대량 읽기를 위한: 중첩 세트(노드에 왼쪽/오른쪽 경계를 저장하여 자손을 빠르게 검색)
  • 자주 변경되는 경우: 인접 목록 + 재귀 CTE
  • 경로를 빠르게 검색하기 위해 — 경로 및 문자열에 전체 경로 저장

재귀적 하위 트리 검색 예시 CTE:

WITH RecursiveTree AS ( SELECT id, parent_id, name, 0 as level FROM categories WHERE parent_id IS NULL UNION ALL SELECT c.id, c.parent_id, c.name, rt.level + 1 FROM categories c INNER JOIN RecursiveTree rt ON c.parent_id = rt.id ) SELECT * FROM RecursiveTree;

주요 특징:

  • 시나리오에 맞는 저장 구조 선택(Parent-Child, 중첩 세트, 경로)
  • 임의의 깊이를 위한 재귀 CTE 사용
  • 최적의 방법을 찾기 위한 변경 및 읽기 빈도 평가

함정 질문.

깊이가 고정된 경우 트리를 하나의 비정규화된 테이블로 대체할 수 있나요?

깊이가 작고 항상 고정되어 있는 경우(2-3단계)만 가능하지만, 그 이후에는 JOIN이 관리 불가능해지고 변경 처리도 복잡해집니다.


CTE가 큰 트리에서 "중단"되지 않을까요? 스택이나 재귀 깊이에 제한이 없나요?

네, 대부분의 DBMS는 재귀 깊이에 대한 제한(예: 100/32767)을 설정해 놓습니다. 1000단계 이상의 트리에서는 깊이를 수동으로 관리하거나 사용자 정의 탐색/분할 알고리즘이 필요합니다.


중첩 세트가 모든 문제를 해결합니까?

아니요, 중첩 세트는 모든 자손을 즉시 찾지만, 삽입/삭제는 모든 인덱스를 왼쪽/오른쪽으로 업데이트해야 하므로 잦은 변경이 있을 때는 느려집니다.

삽입 예시(단순화됨):

UPDATE tree SET lft = lft + 2 WHERE lft > @parent_right; UPDATE tree SET rgt = rgt + 2 WHERE rgt >= @parent_right; INSERT INTO tree(id, name, lft, rgt) VALUES(@new_id, @name, @parent_right, @parent_right + 1);

일반적인 오류 및 안티 패턴

  • 깊은 트리에서 Parent-Child가 쉽게 확장될 것이라고 기대함 — 빠른 비용 증가
  • 업데이트된 데이터에 대한 중첩 세트(삽입/삭제) — 비용이 많이 듭니다.
  • 큰 트리에서 CTE/스택 오버플로우 제한 무시

실제 사례

부정적 사례

큰 인터넷 쇼핑몰은 인접 목록에서 카테고리 트리를 저장하고 중첩 서브쿼리로 메뉴를 구성했습니다. 6단계 이상의 메뉴에서 주요 쿼리는 몇 분이 걸렸고, 트리의 변경은 cascade update로 이어졌습니다. 장점:

  • 간단한 코드
  • 표준 SQL 스키마 지원

단점:

  • 느린 탐색, 집계 및 보고서 작성이 어려움

긍정적 사례

정적 트리(카테고리)에 대해 중첩 세트로 전환하고 메뉴 경로에는 경로를 사용했습니다. 동적 시나리오에 대해 CTE를 사용했습니다. 자손 검색이 즉시 이루어지고 변경 작업이 배치로 수행되었습니다. 장점:

  • 모든 수준의 빠른 검색
  • 유연성, 다양한 작업을 위한 다양한 모델

단점:

  • 변경 시 경계 무결성 관리 필요(중첩 세트)
  • 마이그레이션 시 동기화의 복잡성 증가