MySQL N+1 query 가이드: 왜 ORM을 쓰는데도 느려질까
DB

MySQL N+1 query 가이드: 왜 ORM을 쓰는데도 느려질까


애플리케이션 코드를 보면 깔끔해 보이는데, 실제 DB 성능은 이상하게 나쁜 경우가 있습니다. 특히 ORM을 쓸 때 자주 만나는 대표적인 문제가 N+1 query입니다.

이 글에서는 아래 내용을 정리합니다.

  • N+1 query가 무엇인지
  • 왜 ORM 환경에서 자주 생기는지
  • 왜 성능을 크게 망칠 수 있는지
  • 어떻게 줄일 수 있는지

핵심은 N+1 문제는 쿼리 하나의 성능보다, 쿼리 개수가 불필요하게 폭증하는 구조 문제라는 점입니다.

N+1 query란 무엇인가

예를 들어 게시글 목록 100개를 읽은 뒤, 각 게시글의 작성자 정보를 하나씩 다시 조회한다고 생각해보겠습니다.

그러면:

  1. 게시글 목록 1번 조회
  2. 작성자 조회 100번 추가

가 되어 총 101개의 쿼리가 발생합니다. 이게 대표적인 N+1 구조입니다.

왜 ORM에서 자주 생길까

ORM은 객체 접근이 자연스럽다 보니, 코드에서는 단순히:

  • post.author

처럼 보일 수 있습니다. 하지만 내부적으로는 각 접근마다 쿼리가 나갈 수 있습니다.

즉, 코드가 깔끔해 보여도 실제 쿼리 수는 크게 늘어날 수 있습니다.

왜 성능을 크게 망칠까

N+1 문제는 개별 쿼리가 아주 느리지 않아도 전체로는 비용이 커집니다.

왜냐하면:

  • DB round trip이 많아지고
  • 네트워크 비용이 누적되며
  • 동시 트래픽에서 연결 점유가 늘고
  • 응답 시간이 길어질 수 있기 때문입니다

즉, 한 번 한 번은 가벼워 보여도 총합이 병목이 됩니다.

어떤 식으로 줄일 수 있을까

대표적인 방법은 아래와 같습니다.

  • 필요한 관계를 미리 함께 조회
  • JOIN이나 eager loading 활용
  • 한 번에 묶어서 조회하는 batch 패턴 사용

중요한 것은 “코드에서 필요한 데이터 구조”를 미리 보고, 그에 맞춰 쿼리 수를 줄이는 것입니다.

언제 특히 조심해야 할까

아래 같은 곳에서 특히 자주 보입니다.

  • 목록 화면
  • 댓글/작성자/태그 등 관계 데이터
  • 관리자 페이지의 통계형 조회

즉, 한 개의 부모 row 아래 여러 관계를 따라가면서 데이터를 붙이는 화면에서 자주 터집니다.

자주 하는 오해

1. ORM이 알아서 최적화해준다

일부 도움은 있지만, 관계 조회 패턴까지 항상 자동으로 최적화해주지는 않습니다.

2. 각 쿼리가 빠르면 괜찮다

쿼리 수가 많으면 총 비용이 충분히 커질 수 있습니다.

3. JOIN만 쓰면 무조건 해결된다

관계와 데이터량에 따라 eager loading, batching 등 다른 접근이 더 나을 수도 있습니다.

FAQ

Q. N+1은 어떻게 빨리 발견하나

쿼리 로그, ORM 디버그 로그, 그리고 목록 페이지에서 쿼리 수를 세어보는 습관이 도움이 됩니다.

Q. 작은 서비스도 신경 써야 하나

초반에는 덜 보일 수 있지만, 데이터가 늘면 갑자기 문제로 드러날 수 있습니다.

Q. JOIN이 많아지면 또 느려지지 않나

그럴 수 있습니다. 중요한 것은 쿼리 수와 쿼리 복잡도 사이의 균형을 보는 것입니다.

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.