자기 참조 테이블에서 댓글 중첩 깊이 제한하는 방법
Source: Dev.to
Introduction
댓글 시스템(예: Reddit이나 기술 블로그)을 자체 참조 관계로 구축할 때, 각 댓글은 다른 댓글을 부모로 참조할 수 있습니다. 이는 무한 중첩을 가능하게 하지만, 깊은 재귀는 UI 가독성과 성능에 악영향을 줍니다. 흔히 요구되는 것이 중첩 깊이를 제한하는 것(예: 최대 5단계)입니다.
Standard Adjacency List Model
CREATE TABLE comment (
id BIGINT PRIMARY KEY,
parent_id BIGINT, -- References id
content TEXT
);
이 스키마에서 깊이 제한을 강제하려면 매 삽입 시 재귀 CTE를 사용해야 하는데, 이는 비용이 많이 듭니다.
Database Schema Update
중첩 레벨을 명시적으로 저장하기 위해 depth(또는 level) 컬럼을 추가합니다.
CREATE TABLE comment (
id BIGINT PRIMARY KEY,
parent_id BIGINT,
content TEXT,
depth INT DEFAULT 1 -- 1 for root comments
);
Application Logic (JPA Example)
새 댓글을 만들 때는 부모 댓글의 깊이만 확인하면 됩니다.
Steps
- 부모 댓글을 조회합니다.
- 깊이 검증:
parent.depth >= MAX_DEPTH이면 답글을 거부합니다. - 자식 깊이 설정:
child.depth = parent.depth + 1.
Best‑Practice Code (Spring Boot / Java)
@Service
@RequiredArgsConstructor
public class CommentService {
private final CommentRepository commentRepository;
private static final int MAX_DEPTH = 5;
@Transactional
public void addReply(Long parentId, String content) {
// 1. Fetch Parent
Comment parent = commentRepository.findById(parentId)
.orElseThrow(() -> new EntityNotFoundException("Parent not found"));
// 2. Validate Depth
if (parent.getDepth() >= MAX_DEPTH) {
throw new IllegalArgumentException(
"Comments cannot be nested deeper than " + MAX_DEPTH + " levels.");
}
// 3. Create Child
Comment reply = Comment.builder()
.content(content)
.parent(parent)
.depth(parent.getDepth() + 1) // Calculate depth immediately
.build();
commentRepository.save(reply);
}
}
Read Performance
깊이가 저장되어 있기 때문에 재귀 없이도 댓글을 필터링할 수 있습니다. 예:
SELECT * FROM comment WHERE depth < 5;
Write Performance
깊이 검증은 O(1) 입니다: 부모 레코드만 필요하며, 이는 보통 이미 로드된 상태입니다.
UI Friendly
API 응답에 depth 필드를 노출합니다. 프론트엔드에서는 이 값을 이용해 쉽게 들여쓰기를 적용할 수 있습니다. 예: margin-left: depth * 20px.
Conclusion
단순한 depth 정수 컬럼을 저장함으로써 얻을 수 있는 장점:
- 즉시 검증 로직 구현.
- 읽기/쓰기 쿼리 속도 향상.
- UI 처리 간소화.
삽입 시 재귀 쿼리를 피하고, 대신 비정규화된 depth 컬럼을 활용하세요.