Core와 ORM의 차이점 정리
항목 | Core 방식 | ORM 방식 |
선언 방식 | Table(...) 객체로 직접 정의 | Python 클래스(class)로 선언 |
쿼리 스타일 | SQL과 유사한 스타일 | 객체지향적으로 표현 |
사용 목적 | SQL에 가까운 제어 필요할 때 | 모델 중심의 개발에 적합 |
가독성 | SQL처럼 보임 | 도메인 객체처럼 읽힘 |
자동완성 / IDE 지원 | 거의 없음 | 매우 좋음 (클래스 기반) |
마이그레이션 연동 | 자동 불가 (수동 필요) | Alembic 자동 인식 가능 |
Core 방식 - 테이블 중심, SQL 중심
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")
- 스키마를 동적으로 바꿔야 할 때
- 복잡한 SQL 문을 직접 짜야할 때
- ORM 쓰기 어려운 메타 프로그래밍 상황
ORM 방식 – 객체 중심, 유지보수 중심
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")
- 모델 중심 개발이 필요할 때
- 자동 마이그레이션(Alembic)연동 할 때
- FastAPI, Pydantic, IDE와의 통합이 중요할 때
- 협업/대규모 유지보수 환경
선택 기준
상황 | 추천 방식 |
단순 앱, 유지보수 중심 | ✅ 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)
요약
- ORM은 유지보수에 강하고 생산성이 높다
- Core는 유연성과 복잡 쿼리에 강하다
- 둘 다 SQLAlchemy의 일부이며, 혼용도 가능하다
- 설계는 ORM, 세부 제어는 Core로 접근하자