Framework & Library/Spring

[Spring Boot/JPA] FetchType, Lazy Loading

sechoi 2023. 6. 13. 00:17

데이터베이스의 두 테이블이 (일대다 혹은 다대일) 연관 관계를 맺을 때 FK를 통해 연결된다. FK는 연결 된 테이블의 PK이다.

하지만 JPA를 사용하면 코드에서 PK가 아닌 PK가 나타내는 테이블 자체로 연결한다.

 

원래는 코드에서 다음과 같이 연관관계를 나타낸다면,

public class Member {

    // 나머지 컬럼 생략
    Long teamId;
    
}

public class Team {
    
    Long id;
    
}

 

JPA는 해당 객체 자체로 연관관계를 나타낸다.

public class Member {

    @ManyToOne
    @JoinColumn(name = "team_id")
    Team team;
    
}

 

그렇다고 해서 데이터베이스의 테이블이 변하지는 않는다. 실제 member 테이블에는 똑같이 team_id 라는 FK가 있다.

그러나 해당 Member 객체를 불러오는 순간 그와 연결 된 Team 객체 또한 같이 불러오게 된다. 

 

Eagerly fetching

이렇게 어떠한 객체를 조회할 때, 연관 된 객체까지 바로 조회하는 것을 즉시 로딩이라고 한다. JPA에서는 join을 사용 해 두 객체를 한 번에 조회한다. 

 

따라서 연관 된 객체까지는 조회가 필요없는 경우에도 강제적으로 join을 날려야 한다. 이 때는 그래도 쿼리를 하나만 날리지만, 한 번에 여러 객체를 조회하는 상황이면? 여러 객체를 가져온 후, 각각 객체와 연결된 객체를 다시 조회해서 가져와야 하는 것이다. 이를 N + 1 문제라고 한다. 쿼리를 하나만 날렸는데 추가적으로 N개의 쿼리가 나간다는 의미이다. 웁스

 

Lazy loading

public class Member {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    Team team;
    
}

이와 반대되는 개념이 바로 지연 로딩이다. 지연 로딩은 연관 된 객체를 실제 객체가 아닌 프록시 객체로 가져온다. 연관 된 객체의 필드에 접근하는 등 실제 객체를 사용해야 하는 시점에서야 쿼리를 날려 실제 객체를 조회한다. 따라서 위에서 언급 된 즉시 로딩의 문제점들을 해결할 수 있다.

 

두 객체를 동시에 조회해야 하는 상황에서는 즉시 로딩이 하나의 쿼리로 두 객체를 조회하므로 빠르다. 하지만 실무에서는 데이터가 방대하고 이 때 즉시 로딩의 문제점은 성능에 치명적이기 때문에 지연 로딩을 사용하는 대신, JPQL의 Fetch Join을 사용한다고 한다.

 

https://offetuoso.github.io/blog/develop/backend/orm-jpa-basic/jpql-fetch-join/

 

JPQL 페치 조인(Fetch Join)

JPQL 페치 조인(Fetch Join)

offetuoso.github.io