재귀적 쿼리는 쿼리 자체를 반복해서 실행하는 방식으로, 계층 구조나 그래프 형태의 데이터를 탐색할 때 특히 유용하다. 대부분의 관계형 데이터베이스 관리 시스템(RDBMS)에서는 Common Table Expressions (CTE)를 사용하여 재귀적 쿼리를 작성할 수 있다.
작동 원리
재귀적 쿼리는 기본적으로 두 부분으로 나뉜다:
- 기본 케이스 (Base case): 쿼리의 초기 결과를 반환한다.
- 재귀 케이스 (Recursive case): 이전 단계의 결과를 활용하여 추가적인 결과를 반환한다.
이 두 부분은 CTE 내에서 UNION이나 UNION ALL 연산을 사용하여 결합된다.
유용한 사용 시나리오
재귀적 쿼리는 다음과 같은 상황에서 유용하다:
- 계층 구조 데이터 탐색: 댓글과 대댓글 관계, 조직의 직원 및 관리자 관계, 카테고리와 하위 카테고리 관계 등
- 그래프 데이터 탐색: 소셜 네트워크의 친구 관계, 최단 경로 찾기 등
- 연속 날짜 생성: 주어진 날짜 범위 내의 모든 날짜 목록을 생성할 때
가상 시나리오:
블로그나 포럼과 같은 웹 사이트에서 사용자들은 게시물에 댓글을 남길 수 있습니다. 또한, 댓글에는 다른 사용자들이 대댓글을 남길 수 있습니다. 이런 구조는 댓글, 대댓글, 대-대댓글과 같이 계속 확장될 수 있는 계층 구조를 형성합니다.
Entity Relationship (ER):
- Comments
comment_id
(Primary Key)content
post_id
(Foreign Key, 해당 댓글이 어떤 게시물에 속하는지 지정)parent_comment_id
(Foreign Key,Comments.comment_id
를 참조. 대댓글의 경우, 이를 통해 원 댓글을 찾을 수 있다. 최상위 댓글의 경우 NULL)
parent_comment_id
는 Comments
테이블의 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_id
는 Employee
테이블의 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;
이 쿼리는 특정 관리자의 모든 부하직원을 재귀적으로 조회한다. 처음에는 직접적인 부하직원만을 조회하고, 그 다음 단계에서는 해당 부하직원의 부하직원을 조회하는 식으로 계속된다.
마무리
재귀적 쿼리는 복잡한 데이터 구조를 탐색하고 분석하는 데 유용한 도구다. 하지만 복잡성과 성능 문제로 인해 잘 사용해야 한다. 항상 실행 계획을 확인하고, 필요한 경우 최적화를 고려해야 한다.
'데이터베이스' 카테고리의 다른 글
[트랜잭션 시리즈 - 2] 트랜잭션 격리 수준별 대표적인 트러블 케이스 정리 (2) | 2025.03.24 |
---|---|
[트랜잭션 시리즈 - 1] 트랜잭션의 격리 수준 정리 (0) | 2025.03.24 |
MySQL `EXPLAIN`의 조인 타입(`type` 컬럼) 깊게 이해하기 (0) | 2023.09.12 |
MySQL `EXPLAIN`의 이해와 활용 (0) | 2023.09.12 |
복합키란 무엇인가? (1) | 2023.09.06 |