본문 바로가기
Project/mo:rack (익명 커뮤니티)

댓글 조회 리팩토링중 - feat.인덱스

by 창브로 2025. 6. 18.

전에 게시글들을 보았으면 내가 얼마나 멍청하게 댓글들을 불러왔는지 알 수 있다.

사실 블로그에 글을 쓰고 인지를 하여 그냥 모든 개발이 끝나고 리팩토링 해야지 했는데 자꾸 걸려서 미리 리팩토링 하게 되었다.

 

 

전에는 댓글을 페이지네이션 하나 없이 모든 댓글 + 대댓글을 다 불러왔다. 사실 소량의 데이터면 상관은 없는데

사용자의 사용성은 나눠서 보여주는 게 낫기 때문에 한 번에 다 보여주는 것보단

대댓글은 숨기고 보여주고 할 필요가 있다고 생각했다.

 

페이지네이션은 잘 마쳤다!

(페이지네이션에 대한 내용은 전에 게시글 페이지네이션 했던 글 봐주세요)

 

이제 댓글에 대댓글이 있는지 정보를 클라이언트에 보내줘야 클라이언트가

-대댓글 더보기..- 

 

뭐 이런 UI를 달아줄 수 있기 때문이다.

 

백엔드 쪽에선 단순히 true/false만 판단하면 되니까

"이건 가볍겠지" 라고 생각했다.

그래서 아래처럼 jpa를 사용하여 호출했다

 

commentRepository.existsByParentComment(comment);

 

 

이렇게 사용하여 실행하여 로그에 찍힌 쿼리를 보고

살짝 멈칫했다.

SELECT 1 FROM comment WHERE parent_comment_id = ? LIMIT 1;

 

 

쿼리는 단순하다.

parent_comment_id가 내가 찾는 댓글의 ID인 row가 있는지만 보면 된다.

 

근데 DB가 이걸 찾는 방법이 문제다.

 

WHERE parent_comment_id = ? <- 조건

parent_comment_id에 인덱스가 없으면 DB는

 

comment 테이블의 모든 행을 처음부터 끝까지 다 흝으면서, parent_comment_id가 내가 찾는 값이랑 같은 게 있나 찾아본다!!!

 

생각만 해도 끔찍하지 않나요?

 

이런 걸 Full Table Scan이라고 부르는데 댓글이 뭐 수십 개 수백 개까진 괜찮아도

수천, 수만(내 프로젝트에서 이럴일은 없지만..)개가 넘어가면 쿼리 속도가 슬슬 느려질 것이다.

 

그래서 나는 인덱스를 사용했다.

 

나는 초기 개발 단계여서 그냥 comment Entity 코드에 인덱스를 정의해 놓았다.

@Entity
@Table(name = "comment", indexes = {
    @Index(name = "idx_parent_comment_id", columnList = "parent_comment_id")
})
public class Comment {
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_comment_id")
    private Comment parentComment;

    // ...
}

 

개발이 이미 진행되고 리팩토링을 할 때는 DB에 직접

 

CREATE INDEX idx_parent_comment_id ON comment (parent_comment_id);

 

이렇게 적어도 된다.

 

 

이렇게 하면 DB가 parent_comment_id만 따로 정리된 구조(B-Tree)에 저장하고 필요할 때 바로 찾아갈 수 있다.

 

살짝 이해가 안 될 수도 있어서 쉽게 풀어보면

 

나처럼 인덱스를 추가하고 나서의 DB는 하나하나 바보처럼 다 찾는 게 아니라

parent_comment_id 컬럼만 따로 정리된 자료구조(B-Tree 인덱스)를 사용해서 찾는다.

 

쉽게 말해

 

parent_comment_id가 123인 row?

어, 인덱스에 있네?! -> 해당 row 위치도 같이 저장돼 있으니 바로 가서 읽자!!

 

 

 

아직도 좀 어려울 수도 있습니다.

 

좀 더 쉽게 보면

 

 

인덱스가 없을 때 (Full Table Scan)

1번 row → parent_comment_id = 123인가? ❌
2번 row → parent_comment_id = 123인가? ❌
3번 row → parent_comment_id = 123인가? ✅ → 결과 리턴!

 

 

 

인덱스가 있을 때 (Index Seek)

인덱스(B-Tree):

parent_comment_id     |   Row 위치
---------------------|---------------
101                  |   2번 row
112                  |   5번 row
123                  |   8번 row  ← 찾는 값
133                  |   10번 row

 

 

인덱스는 책의 목차라고 생각하면 된다!

 

내가 원하는 내용이 있고 목차에 그 내용이 있으면 해당 페이지로 바로 이동하고

목차에 없으면 1페이지부터 끝까지 다 찾아야 하는 느낌이라고 생각하면 된다 ~~

 

이해되셨죠?