애플리케이션 코드를 보면 깔끔해 보이는데, 실제 DB 성능은 이상하게 나쁜 경우가 있습니다. 특히 ORM을 쓸 때 자주 만나는 대표적인 문제가 N+1 query입니다.
이 글에서는 아래 내용을 정리합니다.
- N+1 query가 무엇인지
- 왜 ORM 환경에서 자주 생기는지
- 왜 성능을 크게 망칠 수 있는지
- 어떻게 줄일 수 있는지
핵심은 N+1 문제는 쿼리 하나의 성능보다, 쿼리 개수가 불필요하게 폭증하는 구조 문제라는 점입니다.
N+1 query란 무엇인가
예를 들어 게시글 목록 100개를 읽은 뒤, 각 게시글의 작성자 정보를 하나씩 다시 조회한다고 생각해보겠습니다.
그러면:
- 게시글 목록 1번 조회
- 작성자 조회 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이 많아지면 또 느려지지 않나
그럴 수 있습니다. 중요한 것은 쿼리 수와 쿼리 복잡도 사이의 균형을 보는 것입니다.
Read Next
- 실제 쿼리 계획을 보려면 MySQL EXPLAIN 가이드와 함께 보면 좋습니다.
- 전체 점검 흐름은 MySQL query optimization checklist와 잘 이어집니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.