본문으로 건너뛰기
피드

ORM이 결국 알려준 것: 그냥 SQL을 배우는 게 낫다

backend 약 6분
vote
0
댓글
북마크

ORM은 단순한 CRUD에서는 편하지만, 테이블이 넓어지고 조인이 많아지는 순간 추상화 비용이 확 튄다는 글이다. 저자는 Hibernate 같은 ORM을 쓰면서 SELECT *급 쿼리, 과한 객체 변환, 트랜잭션 경계, 마이그레이션 문제를 겪고 결국 쿼리를 데이터베이스 API처럼 보는 쪽으로 생각이 바뀌었다고 말한다.

  • 1

    ORM은 넓은 테이블에서 불필요한 컬럼과 조인을 끌고 와 성능 문제를 만들기 쉽다

  • 2

    효율적인 쿼리를 쓰려면 결국 SQL을 알아야 하고, 그러면 ORM 쿼리 DSL을 우회하고 싶어진다

  • 3

    데이터 정의와 마이그레이션은 애플리케이션 객체 모델보다 데이터베이스 중심으로 다루는 편이 낫다는 주장이다

  • ORM이 제일 위험해지는 순간은 테이블이 슬슬 살찌기 시작할 때임

    • 처음에는 속성 5개짜리 Foo 엔티티라서 query(Foo.class)가 별문제 없어 보임
    • 그런데 클라이언트 데이터가 계속 붙고, 보고서용 비즈니스 로직 때문에 컬럼이 100개까지 늘어나면 이 코드는 사실상 SELECT *가 됨
    • 저자는 실제로 projection을 추가해서 분 단위로 걸리던 쿼리를 초 단위로 줄였다고 함. 병목은 DB가 아니라 DB row를 Java 객체로 바꾸는 작업이었음
  • 외래 키도 ORM에서는 생각보다 세게 터짐

    • 클래스 간 링크를 외래 키로 표현하고, 설정을 조심하지 않으면 객체 하나 가져오려고 조인이 줄줄이 붙음
    • 저자가 본 사례 중 하나는 단일 객체 접근에 600개 넘는 속성과 14개 조인이 따라붙었음. 와, 이건 객체 하나가 아니라 이삿짐임
  • 결론은 꽤 단순함. ORM을 잘 쓰려면 SQL을 알아야 함

    • 효율이 중요해지는 순간 ORM이 생성하는 SQL을 이해해야 하고, 어떻게 하면 원하는 SQL을 뽑게 할지 역으로 설득해야 함
    • 이럴 거면 그냥 SQL을 쓰는 편이 낫다는 게 저자의 주장임. SQL을 모르는 척하려고 ORM DSL을 배우는 게 더 이상한 그림이라는 것
  • 복잡한 쿼리는 데이터베이스가 더 잘하는데, ORM은 그걸 앱 코드로 끌고 오게 만들 때가 많음

    • 윈도 함수(window function) 같은 SQL 기능은 ORM으로 쓰기 고통스러운 편임
    • 그래서 쿼리를 단순하게 유지하려다 보면 DB에서 빠르게 끝낼 일을 앱으로 대량 전송해서 처리하게 됨
    • 저자는 결국 테이블 표현은 ORM에서 얻고, 쿼리는 템플릿 기반 SQL로 직접 작성하는 절충안을 택함
  • 데이터 정의를 어디에 둘지도 피할 수 없는 중복 문제임

    • 데이터베이스와 애플리케이션 양쪽에 모델 정의가 생김
    • 정의를 앱에만 두면 ORM 코드로 DDL을 써야 하고, 정의를 DB에만 두면 앱에서 문자열 타이핑을 피하기 위한 표현이 또 필요함
    • 저자는 데이터 정의의 원본은 데이터베이스에 두고, 앱에는 편의용 표현을 두는 쪽을 선호함
  • 마이그레이션은 ORM이 별로 도와주지 못하는 영역이라고 봄

    • 앱 모델 바꾸는 건 쉽지만, 데이터베이스는 영속 상태라 스키마 변경이 훨씬 까다로움
    • ORM은 객체 상태 저장에는 관심이 많지만 실제 데이터 마이그레이션 문제를 해결해주지는 않음
    • 그래서 저자는 객체가 아니라 쿼리를 데이터베이스 API로 보고, 반환 타입이 있는 함수처럼 생각하는 쪽으로 갔다고 함
  • 트랜잭션과 identity 문제도 추상화가 새는 정도가 아니라 그냥 넘침

    • 앱에서는 객체 identity가 메모리 위치 같은 의미를 갖지만, DB에서는 식별자가 영속 상태의 일부임
    • ORM을 쓰다 보면 실제 DB id를 얻으려고 cache flush나 partial commit 같은 조작을 해야 할 때가 있음
    • 트랜잭션 경계도 언제 시작되고 끝나는지 계속 신경 써야 해서, 특정 컨텍스트에서만 동작하는 함수가 생기기 쉬움

중요

> 이 글의 핵심은 "ORM 쓰지 마라"보다 "ORM이 SQL 학습을 대체해주지 않는다"에 가까움. RDBMS를 쓴다면 SQL은 결국 피할 수 없는 운영 지식임


기술 맥락

  • 이 글에서 말하는 선택은 ORM을 완전히 버리자는 게 아니라, 쿼리 작성 책임을 어디에 둘지 다시 정하자는 쪽이에요. 객체 모델은 앱에서 편하지만, 실행 계획과 데이터 이동량은 결국 SQL과 데이터베이스가 결정하거든요.

  • 저자가 SQL을 선호하는 이유는 성능 문제가 생겼을 때 관찰 가능한 대상이 명확하기 때문이에요. ORM DSL을 고치면서 어떤 SQL이 나올지 추측하는 것보다, 처음부터 projection과 join을 직접 통제하는 편이 디버깅 경로가 짧아요.

  • 트레이드오프도 있어요. ORM은 타입이 있는 테이블 표현, 반복 CRUD, 관계 탐색을 편하게 해주지만, 복잡한 리포팅 쿼리나 윈도 함수, 대량 데이터 처리에서는 SQL의 표현력을 따라가기 어렵다는 거예요.

  • 실무적으로는 모든 쿼리를 한 방식으로 통일하려고 하기보다, 단순한 쓰기와 조회는 ORM에 맡기고 병목이 되는 읽기 경로는 SQL을 직접 쓰는 식의 혼합 전략이 더 현실적이에요. 저자가 말한 "쿼리가 DB의 API"라는 관점도 이 지점에서 나와요.

2014년 글인데도 지금 백엔드 개발자한테 꽤 잘 꽂힌다. ORM을 버리자는 선언이라기보다, ORM이 SQL을 모르게 해주는 도구라는 환상을 버리라는 쪽에 가깝다.

댓글

댓글

댓글을 불러오는 중...

backend

유니스와프 ‘듀얼풀 훅’, 비활성 자산에서도 수익을 만들 수 있을까

유니스와프가 듀얼풀 훅 감사를 진행 중이며 완료 후 오픈소스로 공개할 계획이라고 전했다. 이 기능은 활성 자산과 비활성 자산 모두에서 수익 전략을 만들 수 있다는 점에서 DeFi 유동성 구조 변화로 언급되고 있다.

backend

EDB, 포스트그레스 AI에 자율 운영 DB와 실시간 분석 기능 추가

EDB가 포스트그레스 기반 AI 데이터 플랫폼에 에이전틱 데이터베이스와 통합 분석 기능을 추가했다. 데이터 이동 없이 관계형·분석·벡터·에이전트 워크로드를 한 플랫폼에서 처리하고, 운영 지표 200개 이상을 모니터링해 튜닝과 문제 대응을 자동화하는 방향이다.

backend

PostgreSQL에서 OOM 킬러가 위험한 이유와 리눅스 커널의 한 글자 버그

Ubicloud가 PostgreSQL에 엄격한 메모리 오버커밋을 쓰는 이유를 설명하다가, 리눅스 6.5 커널의 Committed_AS 누수 버그를 추적한 사례를 공개했음. 8GB 서버에서 651GB가 커밋된 것처럼 보이는 현상이 있었고, 원인은 mremap 경로의 조건문 하나가 잘못 바뀐 커널 버그였음.

backend

EDB 포스트그레스 AI, 데이터베이스가 튜닝하고 에이전트 권한까지 잡는 쪽으로 간다

EDB가 포스트그레스 기반 AI 데이터 플랫폼에 에이전틱 데이터베이스, 통합 분석, 거버넌스 기능을 추가했다. 200개 이상 운영 지표를 모니터링해 튜닝과 문제 대응을 자동화하고, 관계형·분석·벡터 데이터를 단일 SQL 레이어에서 다루겠다는 전략이다.

backend

Databricks가 Postgres 데이터를 S3의 Parquet로 저장해 트랜잭션과 분석을 합치려는 방식

Databricks가 Lakebase와 LTAP 아키텍처를 설명하며, Postgres의 WAL과 데이터 파일을 외부 서비스로 분리하고 운영 데이터는 Parquet 기반 오픈 포맷으로 저장하는 접근을 소개했음. 목표는 CDC나 미러링 없이 하나의 데이터 사본으로 트랜잭션과 분석을 동시에 처리하는 것임.