가장 흔한 ORM 버그
유저 100 명 쿼리. 각 유저마다 그 주문 요청 — 1 + 100 = 101 쿼리. 각 쿼리가 isolation 에선 빠름; round-trip 오버헤드가 페이지 파괴. 이게 N+1 쿼리 문제, 모든 ORM, 모든 프레임워크, 모든 팀에 등장.
발견하는 법
드라이버 레벨 쿼리 로깅 켜고 카운트 봐. 5 쿼리 해야 할 페이지가 500 하면 N+1. Django Debug Toolbar, Rails Bullet, SQLAlchemy events 시스템 같은 도구가 패턴 자동 flag.
세 수정
- Eager loading — 관련 행을 단일 JOIN 또는 단일 IN-clause 에 fetch. 모든 ORM 이 이름 가짐:
selectinload(SQLAlchemy),prefetch_related(Django),includes(Rails). - Raw SQL 의 수동 JOIN — ORM eager-loading 이 어색하면, SQL JOIN 항상 가용.
- Python 아닌 SQL 에서 aggregate — '각 유저마다 주문 카운트' 대신
COUNT(*) ... GROUP BY user_id.