항목 | Core 방식 | ORM 방식 |
---|---|---|
선언 방식 | Table(...) 객체로 직접 정의 | Python 클래스(class)로 선언 |
쿼리 스타일 | SQL과 유사한 스타일 | 객체지향적으로 표현 |
사용 목적 | SQL에 가까운 제어 필요할 때 | 모델 중심의 개발에 적합 |
가독성 | SQL처럼 보임 | 도메인 객체처럼 읽힘 |
자동완성 / IDE 지원 | 거의 없음 | 매우 좋음 (클래스 기반) |
마이그레이션 연동 | 자동 불가 (수동 필요) | Alembic 자동 인식 가능 |
Core는 SQLAlchemy의 "기본 레벨"로,
직접 테이블을 정의하고 SQL처럼 쿼리를 구성한다.
from sqlalchemy import Table, Column, Integer, String, MetaData, select
metadata = MetaData(schema="my_schema")
user_table = Table(
"user", metadata,
Column("id", Integer, primary_key=True),
Column("name", String)
)
stmt = select(user_table).where(user_table.c.name == "Alice")
ORM은 Core 위에서 동작하는 상위 추상화
Python 클래스 기반으로 선언하고 객체처럼 다를 수 있어 유지보수가 쉽다.
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy import Column, Integer, String, select
class Base(DeclarativeBase):
pass
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
stmt = select(User).where(User.name == "Alice")
상황 | 추천 방식 |
---|---|
단순 앱, 유지보수 중심 | ✅ ORM |
테이블 이름/스키마가 동적으로 바뀜 | ✅ Core |
복잡한 JOIN, 윈도우 함수 자주 사용 | ✅ Core |
FastAPI + Alembic 조합 | ✅ ORM |
자동 마이그레이션 필요 | ✅ ORM |
DB 구조를 코드에서 유연하게 제어해야 함 | ✅ Core |
대부분의 실무에서는 ORM으로 전체를 구성하고,
복잡한 일부 쿼리만 Core로 처리하는 혼합 전략이 가장 실용적이다.
# ORM으로 조회
user = await session.get(User, 1)
# Core로 복잡한 SQL 직접 작성
stmt = select(my_table).where(my_table.c.some_func("column") > 5)