ORM을 왜 쓸까?

김한결·2025년 5월 18일

ORM이란?

ORM(Object-Relational Mapping)은 객체 지향 프로그래밍 언어에서 사용하는 객체와 관계형 데이터베이스의 테이블을 매핑해주는 기술입니다. 쉽게 말하면, 자바 같은 언어에서 클래스를 정의하고 나면, 그 클래스와 DB 테이블이 자동으로 연결돼서 SQL문을 직접 작성하지 않고도 DB 조작이 가능해지는 방식을 말합니다.

종류

  • Java - Hibernate
  • Python - SQLAlchemy
  • Ruby - ActiveRecord

JPA란?

Java Persistence API로 자바 ORM기술에 대한 API표준 명세이다. ORM을 사용하기 위한 인터페이스를 모아둔 것이다. 자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스다. "인터페이스"이기 때문에 JPA를 사용하기 위해서는 JPA를 구현한 Hibernate, EclipseLink, DataNucleus와 같은 ORM 프레임워크를 사용해야 한다.
ex) Java에서 JPA를 사용해서 User라는 엔티티 클래스만 만들면 곧바로 user 테이블과 매핑되고, SQL문 없이 userRepository.findById() 같은 코드로 바로 데이터를 조회할 수 있습니다.

ORM의 사용 이유

객체 지향 언어(Java, Python 등)를 쓰는 개발자 입장에서는, 매번 SELECT, INSERT 같은 SQL을 직접 짜지 않아도 되니까 편합니다. 그 대신, 클래스와 속성 중심으로 생각하면서 데이터를 다룰 수 있어서 비즈니스 로직에 더 집중할 수 있습니다.

ORM 장점

1. 객체지향적인 코드로 인해 더 직관적이고 로직에 집중할 수 있도록 도와준다.

  • SQL문이 아닌 클래스의 메소드를 통해 DB를 조작할 수 있으므로 개발자가 객체 모델만 이용해서 로직 개발에 집중할 수 있다.
  • 선언문, 할당, 종료 같은 부수적인 코드가 없거나 줄어든다.
  • 객체마다 코드를 별도로 작성하기 때문에 코드의 가독성이 높아진다.
  • SQL의 절차적이고 순차적인 접근이 아닌 객체지향적인 접근으로 인해 생산성을 높여준다.

2. 재사용 및 유지보수의 편리성이 증가한다.

  • ORM은 독립적으로 작성되어있고, 해당 객체들을 재활용할 수 있다.
  • 매핑 정보가 명확하여, ERD를 보는 것에 대한 의존도를 낮출 수 있다.

3. DBMS(Database Management System)에 대한 종속성이 줄어든다.

  • 대부분 ORM 솔루션은 DB에 종속적이지 않기 때문에 구현 방법 뿐만아니라 많은 솔루션에서 자료형 타입까지 유효하다. (종속성 : 어떤 코드, 모듈, 클래스, 시스템이 다른 것에 의존하고 있는 관계)
  • 개발자는 Object에 집중함으로 극단적으로 DBMS를 교체하는 큰 작업에도 적은 리스크와 시간이 소요된다. (DIP)
  • 또한 자바에서 가공할 경우 equals , hashcode 의 오버라이드 같은 자바의 기능을 이용할 수 있고, 간결하고 빠른 가공이 가능하다.

ORM의 한계

1. N+1 문제

ORM(JPA, Hibernate, SQLAlchemy 등)을 사용할 때, 1번의 쿼리로 해결할 수 있는 작업이 N+1번의 쿼리로 실행되는 비효율적인 상황을 말합니다.

EX

  • 팀(team)와 선수(player)은 1:N 관계
  • 즉, 하나의 팀에 여러 명의 선수들이 있습니다.
List<Team> teamList = teamRepository.findAll(); // 쿼리 1번
for (Team team : teamList) {
    List<Player> playerList = team.getPlayerList(); // 팀마다 쿼리 실행 (N번)
}
  • findAll() → 모든 팀 가져오는 쿼리 1번
  • 각 부서의 getPlayerList() → 팀 수(N)만큼 쿼리
    → 즉, 총 N+1번의 쿼리가 실행됩니다.

문제인 이유

1. 데이터가 많아지면 쿼리 수도 기하급수적으로 증가
2. 성능 저하, DB 부하 증가
3. 불필요한 네트워크 비용

해결 방법

@Query("SELECT t FROM Team t JOIN FETCH t.players")
List<Team> findAllWithPlayers();

2. 성능

메서드 호출로 쿼리를 실행한다는 것은 내부적으로 많은 동작이 있다는 것을 의미하므로, 직접 SQL을 호출하는 것보다 성능이 떨어질 수 있습니다. 실제로 초기의 ORM은 쿼리가 제대로 수행되지 않았고, 성능도 좋지 못했다고 합니다.
(그러나 지금은 많이 발전하여, 좋은 성능을 보여주고 있고 계속 발전하고 있습니다.)

3. JPA의 Query Methods만으로는 조회가 불가능한 경우

EX

  • 데이터를 조회할때 조건이 복잡한 경우

@Query란?

  • 더 구체적인 쿼리 메서드를 작성하기 위해 사용하는 쿼리 메서드의 custom버전
public interface UserRepository extends JpaRepository<User, String> {

    @Query(value = "select user " +
            "from User user " +
            "where user.name = :name")
    List<User> findByName(@Param("name") String name);
}

SQL과 ORM 함께 쓰는 이유

ORM은 생산성, 유지보수, 객체지향 프로그래밍에 편리함을 주지만,
복잡하거나 최적화가 필요한 쿼리에서는 성능이 떨어질 수 있습니다.
반대로 직접 SQL을 쓰면 더 세밀하게 쿼리를 최적화할 수 있지만,
코드가 복잡해지고 유지보수가 어려워질 수 있습니다.

함께 쓰는 전략

1. 기본적인 CRUD는 ORM 사용

  • select, insert, update, delete 같은 기본 작업은 ORM으로 처리
    → 코드가 깔끔하고 일관성 유지, 생산성 상승
  • ex) JPA의 save(), findById(), delete() 등과 같은 메서드

2. 복잡하거나 성능 중요한 쿼리는 직접 SQL 작성

  • 복잡한 조인, 집계, 서브쿼리 등 최적화가 필요한 부분은 직접 SQL로 작성
  • Native Query, JDBC Template, MyBatis 같은 도구 사용 가능
  • ex) JPA에서는 @Query(nativeQuery = true)로 네이티브 SQL 사용

3. ORM이 지원하는 쿼리 기능 적극 활용

  • JPQL, Criteria API, QueryDSL 같은 ORM 내 쿼리 빌더 활용
  • 직접 SQL보다 객체 지향적이고 안전한 쿼리 작성 가능

4. ORM과 SQL 혼용 시 일관성 유지

  • 트랜잭션 관리, 데이터 변경 시 ORM과 SQL이 충돌하지 않도록 주의

백엔드 개발자는 SQL을 얼마나 잘 알아야 할까?

나의 생각은 sql의 작동원리 까지는 몰라도 기본적인 개념과 사용방법은 완벽히 다 알고 있어야 된다고 생각한다. 왜냐하면 현대의 웹 & 앱플리케이션에서 DB에 대한 접근이 필수적이기 때문에 그 도구인 SQL을 잘 모른다면 데이터에 대한 관리를 제대로 할 수 없기 때문에 그 웹 & 앱플리케이션 서비스를 이용하기 위험해지기 때문이다.
다양한 이유가 있겠지만 지금처럼 AI가 거의 다 해주는 세상에서 조금이라도 경쟁력이 있을려면 알고 있어야 한다고 생각한다.

출처

https://f-lab.kr/insight/understanding-orm
https://dev-coco.tistory.com/73
https://ccomccomhan.tistory.com/131
https://velog.io/@xogml951/JPA-N1-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0-%EC%B4%9D%EC%A0%95%EB%A6%AC
https://victorydntmd.tistory.com/195
https://velog.io/@bo-ram-bo-ram/JPQL

0개의 댓글