본문으로 건너뛰기
데이터베이스 기초집LESSON 16

ORM과 Raw SQL의 역할 분리

난이도초급 → 중급
예상 시간35분
선수지식이전 강의

16강. ORM과 Raw SQL의 역할 분리

1. 이번 강의에서 해결할 문제​

모든 쿼리를 ORM 관계 탐색으로 작성하면 N+1과 복잡한 집계가 숨겨지고, 모든 것을 문자열 SQL로 작성하면 모델 변경과 타입 검증 비용이 커집니다. 쓰기 모델과 분석 조회에 맞는 도구를 선택합니다.

2. 학습 목표​

3. 핵심 개념​

ORM은 행을 객체로 매핑하고 관계·변경 추적을 제공해 일반 CRUD에 유리합니다. Core와 Raw SQL은 윈도 함수, CTE, DB 고유 기능, 실행 계획 최적화가 중요한 조회를 명확히 표현할 수 있습니다. 선택 기준은 취향이 아니라 쿼리 복잡도, 변경 빈도, 성능 가시성, 팀 역량입니다.

4. 단계별 예시​

파일 경로: C:\dev\game-ranking-service\app\repositories\ranking.py

app/repositories/ranking.py
from sqlalchemy import Select, select, text
from sqlalchemy.orm import Session

from app.models import Player


def find_player(session: Session, player_id: int) -> Player | None:
statement: Select[tuple[Player]] = select(Player).where(Player.id == player_id)
return session.scalar(statement)


RANKING_SQL = text("""
SELECT player_id, nickname, rating,
dense_rank() OVER (ORDER BY rating DESC) AS rank_position
FROM ranking.players
WHERE deleted_at IS NULL
ORDER BY rating DESC, player_id
LIMIT :limit
""")


def get_top_ranking(session: Session, limit: int = 100):
return session.execute(RANKING_SQL, {"limit": limit}).mappings().all()
PowerShell · 테스트 실행
python -m pytest .\tests\repositories\test_ranking.py -q

5. 동작 원리​

두 함수 모두 같은 요청 Session을 받아 동일한 연결·트랜잭션 경계를 사용할 수 있습니다. text()의 :limit 바인드 변수는 값을 SQL 구조와 분리합니다. Raw SQL이라고 문자열 보간을 사용하지 않으며 결과는 mappings()로 명시적인 키 기반 행으로 받습니다.

6. 자주 하는 실수와 해결법​

7. 직접 실습​

8. 이해 점검 질문 3개​

9. 핵심 요약​

MINI QUIZ

ORM과 Raw SQL의 역할 분리 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“ORM과 Raw SQL의 역할 분리” 코드 리뷰에서 유지해야 할 설계 원칙은 무엇인가요?
  2. 문제 2‘ORM 관계를 반복 접근해 N+1 발생’ 상태에 관한 “ORM과 Raw SQL의 역할 분리” 본문의 설명으로 가장 알맞은 것은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

16강. ORM과 Raw SQL의 역할 분리 미완료 상태