본문 바로가기
데이터베이스

재귀적 쿼리에 대한 이해

by 시니성 2023. 9. 20.

재귀적 쿼리는 쿼리 자체를 반복해서 실행하는 방식으로, 계층 구조나 그래프 형태의 데이터를 탐색할 때 특히 유용하다. 대부분의 관계형 데이터베이스 관리 시스템(RDBMS)에서는 Common Table Expressions (CTE)를 사용하여 재귀적 쿼리를 작성할 수 있다.

작동 원리

재귀적 쿼리는 기본적으로 두 부분으로 나뉜다:

  1. 기본 케이스 (Base case): 쿼리의 초기 결과를 반환한다.
  2. 재귀 케이스 (Recursive case): 이전 단계의 결과를 활용하여 추가적인 결과를 반환한다.

이 두 부분은 CTE 내에서 UNION이나 UNION ALL 연산을 사용하여 결합된다.

유용한 사용 시나리오

재귀적 쿼리는 다음과 같은 상황에서 유용하다:

  1. 계층 구조 데이터 탐색: 댓글과 대댓글 관계, 조직의 직원 및 관리자 관계, 카테고리와 하위 카테고리 관계 등
  2. 그래프 데이터 탐색: 소셜 네트워크의 친구 관계, 최단 경로 찾기 등
  3. 연속 날짜 생성: 주어진 날짜 범위 내의 모든 날짜 목록을 생성할 때

가상 시나리오:

블로그나 포럼과 같은 웹 사이트에서 사용자들은 게시물에 댓글을 남길 수 있습니다. 또한, 댓글에는 다른 사용자들이 대댓글을 남길 수 있습니다. 이런 구조는 댓글, 대댓글, 대-대댓글과 같이 계속 확장될 수 있는 계층 구조를 형성합니다.

Entity Relationship (ER):

  • Comments
    • comment_id (Primary Key)
    • content
    • post_id (Foreign Key, 해당 댓글이 어떤 게시물에 속하는지 지정)
    • parent_comment_id (Foreign Key, Comments.comment_id를 참조. 대댓글의 경우, 이를 통해 원 댓글을 찾을 수 있다. 최상위 댓글의 경우 NULL)

parent_comment_idComments 테이블의 comment_id를 참조하므로, 재귀적 관계가 형성됩니다.

재귀적 쿼리 예제:

특정 게시물에 속하는 댓글과 해당 댓글의 모든 대댓글을 탐색하는 쿼리:

WITH RECURSIVE CommentTree AS (
    -- 기본 케이스: 최상위 댓글
    SELECT comment_id, content, post_id, parent_comment_id, 1 as depth
    FROM Comments
    WHERE post_id = ? AND parent_comment_id IS NULL  -- 특정 게시물의 ID

    UNION ALL

    -- 재귀 케이스: 대댓글
    SELECT c.comment_id, c.content, c.post_id, c.parent_comment_id, ct.depth + 1
    FROM Comments c
    JOIN CommentTree ct ON c.parent_comment_id = ct.comment_id
)
SELECT * FROM CommentTree
ORDER BY depth, comment_id;

이 쿼리는 특정 게시물에 대한 댓글 및 모든 대댓글을 계층적 순서로 반환합니다. depth 컬럼은 댓글의 깊이를 나타내며, 최상위 댓글은 depth가 1이 됩니다.

마무리:

재귀적 쿼리는 댓글과 대댓글처럼 계층 구조를 가진 데이터를 탐색하거나 분석할 때 매우 유용합니다. 게시물에 달린 모든 댓글과 대댓글을 일관된 방식으로 조회하고자 할 때 이러한 접근법이 필요하게 됩니다.


예제 시나리오 2: 직원-관리자 관계

한 조직에서 직원들은 각자의 상사를 가질 수 있다. 이러한 관계를 통해 최상위 관리자부터 시작하여 하위 직원까지의 계층 구조를 형성한다.

Entity Relationship (ER):

  • Employee
    • employee_id (Primary Key)
    • employee_name
    • manager_id (Foreign Key, Employee.employee_id를 참조)

위와 같은 ER에서 manager_idEmployee 테이블의 employee_id를 참조하므로 재귀적 관계가 형성된다.

재귀적 쿼리 예제

특정 직원의 모든 부하직원을 찾는 쿼리:

WITH RECURSIVE subordinates AS (
    -- 기본 케이스
    SELECT employee_id, employee_name, manager_id
    FROM Employee
    WHERE manager_id = ?  -- 특정 관리자의 ID

    UNION ALL

    -- 재귀 케이스
    SELECT e.employee_id, e.employee_name, e.manager_id
    FROM Employee e
    JOIN subordinates s ON e.manager_id = s.employee_id
)
SELECT * FROM subordinates;

이 쿼리는 특정 관리자의 모든 부하직원을 재귀적으로 조회한다. 처음에는 직접적인 부하직원만을 조회하고, 그 다음 단계에서는 해당 부하직원의 부하직원을 조회하는 식으로 계속된다.


마무리

재귀적 쿼리는 복잡한 데이터 구조를 탐색하고 분석하는 데 유용한 도구다. 하지만 복잡성과 성능 문제로 인해 잘 사용해야 한다. 항상 실행 계획을 확인하고, 필요한 경우 최적화를 고려해야 한다.