Fetch Join vs ์ผ๋ฐ˜ Join(feat.DTO)

HeoSeungYeonยท2022๋…„ 1์›” 27์ผ
6

Spring Study

๋ชฉ๋ก ๋ณด๊ธฐ
6/7
post-thumbnail

๐Ÿ’ก Spring Data JPA๋ฅผ ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ๊ฐ–๊ณ  ์žˆ๋Š” ๋‘ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•ด ์กฐํšŒ๋ฅผ ํ•  ๋•Œ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
์ด์ „ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํ™ฉ์—์„œ ์ง์ ‘ @Query์— Join query๋ฅผ ์ž‘์„ฑํ•˜๋ฉด์„œ N+1 ๋ฌธ์ œ๋ฅผ ์ง์ ‘์ ์œผ๋กœ ํ™•์ธํ•˜๊ณ  ์ฒด๊ฐํ•˜์ง„ ๋ชปํ•˜์˜€๋Š”๋ฐ์š”,
๋‚˜์ค‘์— N+1 ๋ฌธ์ œ์˜ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด์•˜์„ ๋•Œ, @EntityGraph ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ fetch join์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ฑ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ๋‹จ์ˆœํžˆ ์ด๊ฑฐ ๊ทธ๋ƒฅ Join Query ์‚ฌ์šฉํ•˜๋ฉด ๋˜๋Š”๊ฑฐ ์•„๋‹ˆ์•ผ? ๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๋„˜์–ด๊ฐ”์—ˆ์Šต๋‹ˆ๋‹ค ๐Ÿคญย ํ•˜์ง€๋งŒ ์ผ๋ฐ˜ Join๊ณผ Fetch Join ๊ฐ„์˜ ์ฐจ์ด์ ์„ ๋ชจ๋ฅด๊ณ  ์‚ฌ์šฉํ–ˆ๋‹ค๋Š”๊ฒŒ ๊ณ„์† ๋งˆ์Œ์ด ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๐Ÿฅฒย 
๊ทธ๋ž˜์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋‘˜ ๊ฐ„์˜ ์ฐจ์ด์ ์„ ์•Œ์•„๋ณด๊ณ ์ž ํ•ด๋‹น ํฌ์ŠคํŒ…์„ ์ค€๋น„ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿ”ฅ

ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ์„ธํŒ…


User entity


๐Ÿ’ก ์‚ฌ์šฉ์ž(User)๋Š” name์„ ๊ฐ–๋Š”๋‹ค.

public class User {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;

  @Column(name = "name")
  private String name;

}

Post entity


๐Ÿ’ก ๊ฒŒ์‹œ๋ฌผ(Post)๋Š” title, description์„ ๊ฐ–๊ณ , ์‚ฌ์šฉ์ž(User) ํ•œ๋ช…์ด ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.

public class Post {

  @Id
  @GeneratedValue(strategy = GenerationType.SEQUENCE)
  private Long id;

  @ManyToOne(fetch = FetchType.EAGER)
  @JoinColumn(name = "user_id", referencedColumnName = "id")
  private User user;

  @Column
  private String title;

  @Column
  private String description;

}

@BeforeEach setUp Method


๐Ÿ’ก ์‚ฌ์šฉ์ž(user) - ๊ฒŒ์‹œ๋ฌผ(post) ๊ด€๊ณ„๋ฅผ 5๊ฐœ ์ƒ์„ฑํ•œ๋‹ค.

@BeforeEach
voidsetUp() {
  userRepository.deleteAll();
  postRepository.deleteAll();

  System.out.println("==== setUp start ====");

for(int i = 0; i < 5; i++) {
    User user = User.builder()
        .name("user" + i)
        .build();

    userRepository.save(user);

    Post post = Post.builder()
        .title("title" + i)
        .description("description" + i)
        .user(user)
        .build();

    postRepository.save(post);
  }
  System.out.println("==== setUp end ====");

}

1. ํ…Œ์ŠคํŠธ


๐Ÿ’ก ํ…Œ์ŠคํŠธ ์š”๊ตฌ์‚ฌํ•ญ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
"๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๊ณ , ์กฐํšŒํ•œ ๊ฒŒ์‹œ๋ฌผ์˜ ์ž‘์„ฑ์ž ์ด๋ฆ„์„ ์ถœ๋ ฅํ•œ๋‹ค."

A. N+1 ๋ฌธ์ œ๋ฅผ ํ™•์ธํ•œ๋‹ค.


@Test
@DisplayName("N+1๋ฌธ์ œ๋ฅผ ํ™•์ธํ•œ๋‹ค.")
void NplusOneTest() {
  List<Post> posts = postRepository.findAll();

  posts.stream()
      .map(post -> post.getUser().getName())
      .forEach(System.out::println);
}

์‹คํ–‰ ๊ฒฐ๊ณผ

์กฐํšŒํ•˜๊ณ ์ž ํ•˜๋Š” ์—”ํ‹ฐํ‹ฐ(Post)์˜ ๊ฐฏ์ˆ˜(5)๋งŒํผ ๋งคํ•‘๋œ ์—”ํ‹ฐํ‹ฐ(User)์— ๋Œ€ํ•ด ์กฐํšŒ query๋ฅผ ๋‚ ๋ฆฝ๋‹ˆ๋‹ค.

โ†’ N(User ์กฐํšŒ) + 1(Post ์กฐํšŒ)

โ†’ 1๋ฒˆ ์กฐํšŒํ• ๋ ค๊ณ  ํ•˜๋Š”๋ฐ N๋ฒˆ ์กฐํšŒ๋ฅผ ๋”ํ•˜๊ฒŒ ๋˜๋„ค.

โ†’ ์ด๊ฒŒ ๋ฐ”๋กœ N+1 ๋ฌธ์ œ

์ผ๋ฐ˜์ ์œผ๋กœ SQL์„ ๊ณต๋ถ€ํ•˜์˜€๋‹ค๋ฉด ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์žˆ๋Š” ํ…Œ์ด๋ธ”์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ Join ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ•œ ๋ฒˆ์— ์กฐํšŒ๋ฅผ ํ•˜๋ฉด ๋˜๊ฒ ๋„ค ๋ผ๋Š” ์ƒ๊ฐ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด B(Fetch Join), C(์ผ๋ฐ˜ Join) ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

B. Fetch Join ์ฟผ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค. (์„ฑ๊ณต)


Fetch ์กฐ์ธ์œผ๋กœ Post ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฟผ๋ฆฌ

@Query("SELECT p FROM Post p "
      + "JOIN FETCH p.user")
List<Post> findAllByFetchJoin();

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

@Test
  @DisplayName("Fetch Join ์ฟผ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.")
  void fetchJoinTest() {
    List<Post> posts = postRepository.findAllByFetchJoin();

    posts.stream()
        .map(post -> post.getUser().getName())
        .forEach(System.out::println);
  }

์‹คํ–‰ ๊ฒฐ๊ณผ

Hibernate: 
select post0_.id as id1_0_0_, user1_.id as id1_1_1_, post0_.description as descript2_0_0_, post0_.title as title3_0_0_, post0_.user_id as user_id4_0_0_, user1_.name as name2_1_1_ 
from post post0_ 
inner join user user1_ 
on post0_.user_id=user1_.id

// ์ถœ๋ ฅ ๊ฒฐ๊ณผ 
user0
user1
user2
user3
user4

๊ฒฐ๊ณผ ๋ถ„์„

fetch join์„ ์‚ฌ์šฉํ•˜๋‹ˆ ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์—์„œ ๋‹จ์ผ ๊ฒŒ์‹œ๋ฌผ์ด ๊ฐ–๊ณ  ์žˆ๋Š” ์ž‘์„ฑ์ž(User)์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๊นŒ์ง€ ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฌธ์œผ๋กœ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

C. ์ผ๋ฐ˜ Join ์ฟผ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค. (์‹คํŒจ)


์ผ๋ฐ˜ ์กฐ์ธ์œผ๋กœ Post ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฟผ๋ฆฌ

@Query("SELECT p FROM Post p "
      + "LEFT JOIN User u "
      + "ON p.user.id = u.id")
List<Post> findAllByJoin();

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

@Test
@DisplayName("์ผ๋ฐ˜ Join ์ฟผ๋ฆฌ ์‚ฌ์šฉํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.")
void joinTest() {
  List<Post> posts = postRepository.findAllByJoin();

  posts.stream()
      .map(post -> post.getUser().getName())
      .forEach(System.out::println);
}

์‹คํ–‰ ๊ฒฐ๊ณผ

Hibernate: select post0_.id as id1_0_, post0_.description as descript2_0_, post0_.title as title3_0_, post0_.user_id as user_id4_0_ from post post0_ left outer join user user1_ on (post0_.user_id=user1_.id)
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?
Hibernate: select user0_.id as id1_1_0_, user0_.name as name2_1_0_ from user user0_ where user0_.id=?

// ์ถœ๋ ฅ ๊ฒฐ๊ณผ 
user0
user1
user2
user3
user4

๊ฒฐ๊ณผ ๋ถ„์„

์ผ๋ฐ˜ join์„ ์‚ฌ์šฉํ•˜๋‹ˆ ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์—์„œ ๋‹จ์ผ ๊ฒŒ์‹œ๋ฌผ์ด ๊ฐ–๊ณ  ์žˆ๋Š” ์ž‘์„ฑ์ž(User)์˜ id(PK)๊ฐ’๋งŒ ์กฐํšŒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ํ›„ ์กฐํšŒํ•œ user_id๋ฅผ ํ†ตํ•ด N๋ฒˆ์˜ User ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ๋‚ ๋ฆฌ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์–ด๋ผ?!

๋ถ„๋ช… ์ด์ „ ํ”„๋กœ์ ํŠธ์—์„œ ์ผ๋ฐ˜ join์„ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ N+1 ๋ฌธ์ œ๋ฅผ ํ™•์ธํ–ˆ๋Š”๋ฐ, ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด๋‹ˆ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๐Ÿคฆ๐Ÿป

์Š‰ ์Šˆ์Šˆ์Š‰ ์Š‰์Š‰! (ํ”„๋กœ์ ํŠธ ์ฝ”๋“œ ํ™•์ธํ•˜๋Ÿฌ ๊ฐ€๋Š”์ค‘,,,) ๐Ÿ’จ

์ด์ „ ํ”„๋กœ์ ํŠธ์˜ ์ผ๋ฐ˜ join ์ฟผ๋ฆฌ๋ฅผ ํ™•์ธํ•ด๋ณด๋‹ˆ ๋‘ ์—”ํ‹ฐํ‹ฐ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ DTO ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜๊ฐ’์œผ๋กœ ์„ค์ •ํ•œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฉด D(์ผ๋ฐ˜ Join with DTO) ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด N+1 ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

D. ์ผ๋ฐ˜ join์„ ์‚ฌ์šฉํ•˜๊ณ  DTO ๋ฅผ ๋งŒ๋“ค์–ด N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค (์„ฑ๊ณต)


PostUserDTO : user ์ด๋ฆ„๊ณผ post ์ œ๋ชฉ์„ ๊ฐ–๋Š”๋‹ค.

public class PostUserDTO {

  private String userName;

  private String postTitle;

}

์ผ๋ฐ˜ ์กฐ์ธ์œผ๋กœ DTO ๊ฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” ์ฟผ๋ฆฌ

@Query("SELECT new com.example.springbootstudy.domain.PostUserDTO(u.name, p.title) FROM Post p "
      + "LEFT JOIN User u "
      + "ON p.user.id = u.id")
List<PostUserDTO> findAllPostUserByFetchJoin();

ํ…Œ์ŠคํŠธ ์ฝ”๋“œ

@Test
@DisplayName("์ผ๋ฐ˜ Join ์ฟผ๋ฆฌ ์™€ DTO ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•œ๋‹ค.")
void joinWithDTOTest() {
  List<PostUserDTO> postUserDTOS = postRepository.findAllPostUserByFetchJoin();

  postUserDTOS.stream()
      .map(postUser -> postUser.getUserName())
      .forEach(System.out::println);
}

์‹คํ–‰ ๊ฒฐ๊ณผ

Hibernate: select user1_.name as col_0_0_, post0_.title as col_1_0_ from post post0_ left outer join user user1_ on (post0_.user_id=user1_.id)

// ์ถœ๋ ฅ ๊ฒฐ๊ณผ 
user0
user1
user2
user3
user4

๊ฒฐ๊ณผ ๋ถ„์„

JPQL์—์„  ์กฐํšŒ ์ฟผ๋ฆฌ๋ฌธ์—์„œ DTO๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ•ด๋‹น ๊ธฐ๋Šฅ์„ ํ™œ์šฉํ•˜์—ฌ PostUserDTO ๋ฅผ ํ†ตํ•ด ์กฐํšŒ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜๋ฐ›์œผ๋‹ˆ N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

2. Fetch Join ๊ณผ ์ผ๋ฐ˜ Join


์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด Fetch Join๊ณผ ์ผ๋ฐ˜ Join์„ ๊ฒฐ๊ณผ๋กœ์จ ์ฐจ์ด์ ์„ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ์š”,

์šฐ๋ฆฌ๊ฐ€ ํ™•์ธํ–ˆ๋˜ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Fetch Join

  • ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์—์„œ ๋‹จ์ผ ๊ฒŒ์‹œ๋ฌผ์ด ๊ฐ–๊ณ  ์žˆ๋Š” ์ž‘์„ฑ์ž(User)์˜ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํ•˜๋‚˜์˜ ์ฟผ๋ฆฌ๋ฌธ์œผ๋กœ ์กฐํšŒ

์ผ๋ฐ˜ Join

  • ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ์—์„œ ๋‹จ์ผ ๊ฒŒ์‹œ๋ฌผ์ด ๊ฐ–๊ณ  ์žˆ๋Š” ์ž‘์„ฑ์ž(User)์˜ id(PK)๊ฐ’๋งŒ ์กฐํšŒ
  • ๊ทธ ํ›„, ํš๋“ํ•œ user_id๋ฅผ ํ†ตํ•ด User ์กฐํšŒ ์ฟผ๋ฆฌ N๋ฒˆ ์ˆ˜ํ–‰ (FetchType.EAGER)

๊ทธ๋Ÿฌ๋ฉด Fetch Join๊ณผ ์ผ๋ฐ˜ Join์˜ ์ฐจ์ด์ ์€ ๋ฌด์—‡์ผ๊นŒ์š”?

Fetch Join

  • ์กฐํšŒ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์—”ํ‹ฐํ‹ฐ(JOIN) ๊นŒ์ง€ ๋ชจ๋‘ ์กฐํšŒํ•˜์—ฌ ์˜์†ํ™”ํ•œ๋‹ค.
  • ์ฆ‰, 2๊ฐœ์˜ ์—”ํ‹ฐํ‹ฐ ๋ชจ๋‘ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๋กœ ๊ด€๋ฆฌ๋˜์–ด์ง„๋‹ค.

์ผ๋ฐ˜ Join

  • ์กฐํšŒ ์ฃผ์ฒด๊ฐ€ ๋˜๋Š” ์—”ํ‹ฐํ‹ฐ๋งŒ ์กฐํšŒํ•˜๊ณ  ์˜์†ํ™”ํ•œ๋‹ค.
  • ๋งŒ์•ฝ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์—”ํ‹ฐํ‹ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ ๋ณ„๋„์˜ ์กฐํšŒ ์ฟผ๋ฆฌ๋ฌธ์„ ์‹คํ–‰ ํ•ด์•ผ ํ•จ.
    • FetchType.EAGER ์ผ ๊ฒฝ์šฐ, ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์˜์†ํ™”ํ•˜๊ธฐ ์œ„ํ•ด N๋ฒˆ์˜ ์ฟผ๋ฆฌ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ด.
    • FetchType.LAZY ์ผ ๊ฒฝ์šฐ, ์ตœ์ดˆ ์กฐํšŒ์‹œ ํš๋“ํ•œ id ๋กœ ์กฐํšŒ๋ฅผ N๋ฒˆํ•ด์•ผํ•จ.

3. ์ผ๋ฐ˜ Join with DTO


Fetch Join์„ ์‚ฌ์šฉํ•˜์—ฌ N+1๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด ๋‚˜์ด์Šคํ•œ ๋ฐฉ๋ฒ•์ธ ๊ฒƒ์€ ์•Œ๊ฒŒ๋œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ์œ„ ํ…Œ์ŠคํŠธ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋“ฏ์ด ์ฃผ์–ด์ง„ ์š”๊ตฌ์‚ฌํ•ญ์ด ๋‹จ์ˆœํžˆ ๋ฐ์ดํ„ฐ ์กฐํšŒ๋งŒ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋ฉด D(์ผ๋ฐ˜ Join with DTO) ์™€ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋”๋ผ๋„ N+1 ๋ฌธ์ œ ๊ฑฑ์ • ์—†์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. Fetch Join vs ์ผ๋ฐ˜ Join with DTO


๊ทธ๋ ‡๋‹ค๋ฉด Fetch Join ๊ณผ ์ผ๋ฐ˜ Join with DTO ๋ฐฉ๋ฒ•์€ ๊ฐ๊ฐ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ์ข‹์€ ๊ฒƒ์ผ๊นŒ์š”?

Fetch Join


  • ๋‘ ์—”ํ‹ฐํ‹ฐ์˜ ์˜์†ํ™”๊ฐ€ ํ•„์š”๋กœ ํ•  ๋•Œ

Join with DTO


  • ์˜์†ํ™” ์—†์ด ๋ฐ์ดํ„ฐ ์กฐํšŒ๋งŒ ํ•  ์ˆ˜ ์žˆ์„ ๊ฒฝ์šฐ
  • ๋‘ ์—”ํ‹ฐํ‹ฐ์˜ ์ปฌ๋Ÿผ์ด ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ๊ฒฝ์šฐ(ํ•„์š”ํ•œ ์ปฌ๋Ÿผ๋งŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ์Œ)
  • ๊ฒ€์ƒ‰์กฐ๊ฑด์œผ๋กœ ์—ฐ๊ด€๊ด€๊ณ„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ™œ์šฉํ•  ๊ฒฝ์šฐ

5. ํšŒ๊ณ 


์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ Fetch Join, ์ผ๋ฐ˜ Join ๊ทธ๋ฆฌ๊ณ  DTO๋ฅผ ํ™œ์šฉํ•œ ์ผ๋ฐ˜ Join ์ˆ˜ํ–‰ ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ์ฐจ์ด์ ์„ ์งš์–ด๋ณด์•˜๋Š”๋ฐ์š”, ์ง์ ‘ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ ๊ฒฐ๊ณผ๋ฅผ ํ†ตํ•ด ์ฐจ์ด์  ๋ฐ ์‚ฌ์šฉ ์ƒํ™ฉ์— ๋Œ€ํ•œ ์ƒ๊ฐ์„ ํ•  ์ˆ˜ ์žˆ์–ด ์ข‹์•˜๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ํ‹€๋ฆฐ ๋‚ด์šฉ์ด ์žˆ๊ฑฐ๋‚˜ ๊ฐ™์ด ์˜๋…ผํ•˜๊ณ  ์‹ถ์€ ๋‚ด์šฉ์ด ์žˆ์œผ๋ฉด ํ”ผ๋“œ๋ฐฑ ๋ถ€ํƒ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค( ์–ธ์ œ๋‚˜ ํ™˜์˜ ) ๐Ÿ˜Š

์ฐธ๊ณ ๋ฌธ์„œ


[JPA] ์ผ๋ฐ˜ Join๊ณผ Fetch Join์˜ ์ฐจ์ด

[ํ”„๋กœ์ ํŠธ] Join vs Fetch Join

profile
์•ˆ๋…•ํ•˜์„ธ์š”~! ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ํ—ˆ์Šน์—ฐ ์ž…๋‹ˆ๋‹ค :)

0๊ฐœ์˜ ๋Œ“๊ธ€