애플리케이션을 개발할 때, 데이터베이스 성능은 전체 서비스의 응답 속도에 큰 영향을 미칩니다. 여러 성능 저하 원인 중, 개발자가 인지하지 못한 채 반복적인 쿼리를 날려 발생하는 N+1 쿼리 문제는 가장 흔하면서도 치명적인 원인 중 하나입니다.
N+1 문제가 뭐지..?
N+1 문제란, 첫 번째 쿼리의 결과(N개)를 기반으로, 연관된 데이터를 얻기 위해 N번의 추가 쿼리가 발생하는 상황을 말합니다. 즉, 원래는 하나의 쿼리로 끝낼 수 있는 작업을 1 + N개의 쿼리로 처리하여 데이터베이스에 불필요한 부하를 주는 비효율적인 데이터 조회 방식입니다.
간단한 예시를 통해 자세히 알아보겠습니다.
모든 회원의 주문 내역을 조회하고 싶어!
쇼핑몰의 회원(user) 테이블과 주문(orders) 테이블이 있다고 가정해봅시다.
우리의 목표는 "모든 회원의 주문 내역을 가져오는 것"입니다.
N+1 문제가 발생하는 로직은 보통 다음과 같은 순서로 데이터를 요청합니다.
1. 첫 번째 쿼리로 모든 회원의 정보를 가져옵니다. (쿼리 1번)
SELECT id, name FROM user;
이 쿼리로 100명의 회원(N=100) 정보가 조회되었다고 가정하겠습니다.
2. 애플리케이션에서 각 회원의 주문 내역을 얻기 위해 반복문을 실행합니다. (쿼리 N번)
이제 애플리케이션 코드는 위에서 얻은 100명의 회원 ID를 가지고, 각 회원의 주문 정보를 얻기 위해 루프를 돌며 아래 쿼리를 100번 실행합니다.
SELECT * FROM orders WHERE user_id = 1;
SELECT * FROM orders WHERE user_id = 2;
...
SELECT * FROM orders WHERE user_id = 100;
결과적으로, "모든 회원의 주문 내역 조회"라는 단일 기능을 위해 데이터베이스는 총 101번 (1 + 100) 의 쿼리를 실행하게 됩니다. 이는 애플리케이션과 데이터베이스 간의 통신 비용을 급격히 증가시키고, 데이터가 많아질수록 시스템 전체의 성능을 심각하게 저하시킵니다.
간단한 해결 방법!
이 문제의 해결책은 매우 간단합니다.
여러 번에 나눠서 물어볼 것을, JOIN을 사용해 단 한 번의 쿼리로 필요한 모든 데이터를 가져오는 것입니다!
관계형 데이터베이스는 데이터들을 연결하고 합치는 데 최적화되어 있기 때문에, 우리는 그저 데이터베이스에게 원하는 바를 명확히 알려주기만 하면 됩니다.
SELECT u.id, u.name, o.id, o.order_date
FROM user u
LEFT JOIN orders o ON u.id = o.user_id;
이처럼 단일 JOIN 쿼리를 사용하면, 데이터베이스는 회원 정보와 각 회원의 주문 정보를 모두 포함한 결과를 한 번에 반환합니다. 이로써 불필요한 네트워크 통신과 반복적인 쿼리 실행을 막아 성능을 크게 향상시킬 수 있습니다.
'CS > DB' 카테고리의 다른 글
| DB 성능 문제, 구조를 나누는 것부터 시작하기 (0) | 2025.12.28 |
|---|---|
| DBCP가 뭐지..? (0) | 2025.12.28 |
| Transaction 알아보기 (0) | 2025.09.15 |
| Enum VS VARCHAR (0) | 2025.09.15 |
| DB에서 상속은 어떻게 나타내는가? (0) | 2025.09.14 |
