본문 바로가기
C.W.K.
Stream
Lesson 02 of 10 · published

Raw SQL과 ORM을 함께 쓰기

~14 min · apps, orm

Level 0스키마 새싹
0 XP0/86 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

서로 다른 일을 잘하는 두 도구

Django ORM, ActiveRecord, Hibernate 같은 ORM은 행과 객체를 연결하고 반복적인 CRUD와 마이그레이션을 편하게 하며, 정적 타입 언어에서는 형 안전성도 보태. 데이터베이스 차이도 일부 감춰 주지만 그 추상화만 믿고 엔진을 쉽게 바꿀 일은 드물어. Raw SQL은 JOIN, 윈도 함수, CTE, JSONB, 전문 검색, pgvector처럼 데이터베이스의 표현력을 그대로 쓸 수 있어.

질의마다 알맞은 수준을 골라

단순 저장과 조회에는 ORM을 쓰고, 복잡하거나 성능이 중요한 길에서는 같은 연결과 트랜잭션 안에서 SQL로 내려오면 돼. 둘을 섞는 건 실패가 아니라 건강한 경계야.

생성되는 SQL을 읽을 수 있어야 해

N+1, 불필요한 열, 숨은 왕복을 확인하고, 대량 적재에서는 ORM이 숨긴 COPY를 직접 쓸 수 있는지도 봐. 로그와 EXPLAIN으로 실제 SQL을 확인해.

Code

CRUD에 ORM 사용하기·python
from sqlalchemy.orm import Session
from .models import User

with Session(engine) as session:
    user = User(name="Alice", email="alice@example.com")
    session.add(user)
    session.commit()
    print(user.id)
같은 연결에서 복잡한 질의는 직접 SQL로 쓰기·python
# 같은 connection 풀, 같은 트랜잭션, 그러나 표현력 있는 Postgres
result = session.execute(
    text("""
        SELECT u.id, u.name,
               COUNT(o.id) AS order_count,
               SUM(o.total) AS spent
        FROM users u
        LEFT JOIN orders o ON o.user_id = u.id
        WHERE u.created_at >= now() - interval '30 days'
        GROUP BY u.id, u.name
        HAVING COUNT(o.id) >= :min_orders
        ORDER BY spent DESC
        LIMIT :n
    """),
    {"min_orders": 3, "n": 50},
)
for row in result.mappings():
    print(row["name"], row["spent"])

External links

Exercise

복잡한 집계, JSONB 연산, 전문 검색처럼 ORM에서 어색한 질의를 하나 찾아 같은 세션의 직접 SQL로 다시 써. 두 버전의 가독성을 비교하고 각각 어느 경우에 가치가 있는지 설명해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인 — 댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.