์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ

STEP 02 - ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ๋ณด๊ธฐ (Post Details View)

๋ฏธ๋กœ910 2024. 10. 8. 09:21
๐Ÿ’ก
1. Fetch ์ „๋žต ์ดํ•ดํ•˜๊ธฐ: EAGER์™€ LAZY (Fetch) ์ „๋žต์˜ ์ฐจ์ด์ ๊ณผ ๋™์ž‘ ๋ฐฉ์‹์„ ์ดํ•ดํ•œ๋‹ค.
2. Lazy Loading ๋™์ž‘ ๋ฐฉ์‹ ์ดํ•ดํ•˜๊ธฐ: ์ง€์—ฐ ๋กœ๋”ฉ์ด ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๊ณ , ์–ธ์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š”์ง€ ํ•™์Šตํ•œ๋‹ค.
3. ์ง์ ‘ ์กฐ์ธ(Fetch Join) ์‚ฌ์šฉํ•˜๊ธฐ: ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ง์ ‘ ์กฐ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์šด๋‹ค.

 

1. ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ๋ณด๊ธฐ ๊ตฌํ˜„ (Eager Fetching)

๋ชฉํ‘œ: EAGER ํŽ˜์น˜ ์ „๋žต์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ๋ณด๊ธฐ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๊ณ , ์—ฐ๊ด€๋œ ๊ฐ์ฒด๊ฐ€ ์ฆ‰์‹œ ๋กœ๋”ฉ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

package com.tenco.blog_v1.board;

import com.tenco.blog_v1.user.User;
import jakarta.persistence.*;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Timestamp;

@NoArgsConstructor
@Entity
@Table(name = "board_tb")
@Data
public class Board {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY) // ๊ธฐ๋ณธํ‚ค ์ „๋žต db ์œ„์ž„
    private Integer id;
    private String title;
    private String content;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user; // ๊ฒŒ์‹œ๊ธ€ ์ž‘์„ฑ์ž ์ •๋ณด

    // created_at ์ปฌ๋Ÿผ๊ณผ ๋งคํ•‘ํ•˜๋ฉฐ, ์ด ํ•„๋“œ๋Š” ๋ฐ์ดํ„ฐ ์ €์žฅ์‹œ ์ž๋™์œผ๋กœ ์„ค์ • ๋จ
    @Column(name = "created_at", insertable = false, updatable = false)
    private Timestamp createdAt;

    @Builder
    public Board(Integer id, String title, String content, User user, Timestamp createdAt) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.user = user;
        this.createdAt = createdAt;
    }

}

fetch = FetchType.EAGER ๋กœ ์„ค์ •ํ•˜์—ฌ Board ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๋•Œ ์—ฐ๊ด€๋œ User ์—”ํ‹ฐํ‹ฐ๋„ ์ฆ‰์‹œ ๋กœ๋”ฉํ•ฉ๋‹ˆ๋‹ค.

 

package com.tenco.blog_v1.board;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@RequiredArgsConstructor
@Repository // IoC
public class BoardRepository  {

    private final EntityManager em;

    /**
     * ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ ๋ฉ”์„œ๋“œ
     * @param id ์กฐํšŒํ•  ๊ฒŒ์‹œ๊ธ€ ID
     * @return ์กฐํšŒ๋œ Board ์—”ํ‹ฐํ‹ฐ, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด null ๋ฐ˜ํ™˜ 
     */
    public Board findById(int id) {
         return em.find(Board.class, id);
    }

}

 

{{> layout/header}}

<div class="container p-5">

    <!-- ์ˆ˜์ •, ์‚ญ์ œ๋ฒ„ํŠผ -->
    <div class="d-flex justify-content-end">
        <a href="/board/{{board.id}}/update-form" class="btn btn-warning me-1">์ˆ˜์ •</a>
        <form action="/board/{{board.id}}/delete" method="post">
            <button class="btn btn-danger">์‚ญ์ œ</button>
        </form>
    </div>

    <div class="d-flex justify-content-end">
        <b>์ž‘์„ฑ์ž</b> : {{board.user.username}}
    </div>

    <!-- ๊ฒŒ์‹œ๊ธ€๋‚ด์šฉ -->
    <div>
        <h2><b>{{board.title}}</b></h2>
        <hr />
        <div class="m-4 p-2">
            {{board.content}}
        </div>
    </div>

    <!-- ๋Œ“๊ธ€ -->
    <div class="card mt-3">
        <!-- ๋Œ“๊ธ€๋“ฑ๋ก -->
        <div class="card-body">
            <form action="/reply/save" method="post">
                <textarea class="form-control" rows="2" name="comment"></textarea>
                <div class="d-flex justify-content-end">
                    <button type="submit" class="btn btn-outline-primary mt-1">๋Œ“๊ธ€๋“ฑ๋ก</button>
                </div>
            </form>
        </div>

        <!-- ๋Œ“๊ธ€๋ชฉ๋ก -->
        <div class="card-footer">
            <b>๋Œ“๊ธ€๋ฆฌ์ŠคํŠธ</b>
        </div>
        <div class="list-group">
            <!-- ๋Œ“๊ธ€์•„์ดํ…œ -->
            <div class="list-group-item d-flex justify-content-between align-items-center">
                <div class="d-flex">
                    <div class="px-1 me-1 bg-primary text-white rounded">cos</div>
                    <div>๋Œ“๊ธ€ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค</div>
                </div>
                <form action="/reply/1/delete" method="post">
                    <button class="btn">๐Ÿ—‘</button>
                </form>
            </div>
            <!-- ๋Œ“๊ธ€์•„์ดํ…œ -->
            <div class="list-group-item d-flex justify-content-between align-items-center">
                <div class="d-flex">
                    <div class="px-1 me-1 bg-primary text-white rounded">ssar</div>
                    <div>๋Œ“๊ธ€ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค</div>
                </div>
                <form action="/reply/1/delete" method="post">
                    <button class="btn">๐Ÿ—‘</button>
                </form>
            </div>
        </div>
    </div>
</div>

{{> layout/footer}}

 

Fetch ์ „๋žต ์ดํ•ดํ•˜๊ธฐ: EAGER์™€ LAZY (Fetch) ์ „๋žต์˜ ์ฐจ์ด์ ๊ณผ ๋™์ž‘ ๋ฐฉ์‹์„ ์ดํ•ดํ•œ๋‹ค.
 select
        b1_0.id,
        b1_0.content,
        b1_0.created_at,
        b1_0.title,
        u1_0.id,
        u1_0.created_at,
        u1_0.email,
        u1_0.password,
        u1_0.username 
    from
        board_tb b1_0 
    left join
        user_tb u1_0 
            on u1_0.id=b1_0.user_id 
    where
        b1_0.id=?
Hibernate: 
    select
        b1_0.user_id,
        b1_0.id,
        b1_0.content,
        b1_0.created_at,
        b1_0.title 
    from
        board_tb b1_0 
    where
        b1_0.user_id=?
Hibernate: 
    select
        b1_0.id,
        b1_0.content,
        b1_0.created_at,
        b1_0.title,
        b1_0.user_id 
    from
        board_tb b1_0 
    where
        b1_0.id=?

 

์ง€์—ฐ ๋กœ๋”ฉ์„ ํ•˜๋”๋ผ๋„ ๊ฒฐ๊ตญ ์‚ฌ์šฉํ•˜๋Š” ์‹œ์ ์— ๊ฐ์ฒด ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒ ๋œ๋‹ค.
    <div class="d-flex justify-content-end">
        <b>์ž‘์„ฑ์ž</b> : {{ board.user.username }}
    </div>

 

์š”์•ฝ

EAGER ์ „๋žต๊ณผ Lazy ์ „๋žต์— ๋Œ€ํ•œ ์ฐจ์ด์ ์„ ์ดํ•ด ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ๋‘˜ ๋‹ค ์‚ฌ์šฉํ•˜๋”๋ผ๋„ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

: ์ง€์—ฐ ๋กœ๋”ฉ์ด๋”๋ผ๊ณ  ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ ์™€์•ผ ๋œ๋‹ค๋ฉด —> ์ฟผ๋ฆฌ๊ฐ€ ๋‘๋ฒˆ ์ƒ์„ฑ ํ˜ธ์ถœ ๋œ๋‹ค (N + 1 ๋ฌธ์ œ ๋ฐœ์ƒ)

 

BoardController ์ฝ”๋“œ ์ˆ˜์ •
  // ํŠน์ • ๊ฒŒ์‹œ๊ธ€ ์š”์ฒญ ํ™”๋ฉด
  // ์ฃผ์†Œ์„ค๊ณ„ - http://localhost:8080/board/1
  @GetMapping("/board/{id}")
  public String detail(@PathVariable(name = "id") Integer id, HttpServletRequest request) {
      // JPA API ์‚ฌ์šฉ
      // Board board = boardRepository.findById(id);

      // JPQL FETCH join ์‚ฌ์šฉ
      Board board = boardRepository.findByIdJoinUser(id);
      request.setAttribute("board", board);
      return "board/detail";
  }

 

BoardRepository ์ฝ”๋“œ ์ถ”๊ฐ€
package com.tenco.blog_v1.board;

import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

@RequiredArgsConstructor
@Repository // IoC
public class BoardRepository  {

    private final EntityManager em;

    /**
     * ๊ฒŒ์‹œ๊ธ€ ์กฐํšŒ ๋ฉ”์„œ๋“œ
     * @param id ์กฐํšŒํ•  ๊ฒŒ์‹œ๊ธ€ ID
     * @return ์กฐํšŒ๋œ Board ์—”ํ‹ฐํ‹ฐ, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด null ๋ฐ˜ํ™˜
     */
    public Board findById(int id) {
         return em.find(Board.class, id);
    }

    /**
     * JPQL์˜ FETCH ์กฐ์ธ ์‚ฌ์šฉ - ์„ฑ๋Šฅ ์ตœ์ ํ™”
     * ํ•œ๋ฐฉ์— ์ฟผ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ฆ‰, ์ง์ ‘ ์กฐ์ธํ•ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ ์˜ต๋‹ˆ๋‹ค.
     * @param id
     * @return
     */
    public Board findByIdJoinUser(int id) {
        // JPQL -> Fetch join ์„ ์‚ฌ์šฉํ•ด ๋ณด์ž.
        String jpql = " SELECT b FROM board_tb b JOIN FETCH b.user WHERE b.id = :id ";
        return em.createQuery(jpql, Board.class)
                .setParameter("id", id)
                .getSingleResult();
    }

}

User.board ๋„ LAZY๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•จ !!

 

Hibernate: 
    select
        b1_0.id,
        b1_0.content,
        b1_0.created_at,
        b1_0.title,
        u1_0.id,
        u1_0.created_at,
        u1_0.email,
        u1_0.password,
        u1_0.username 
    from
        board_tb b1_0 
    join
        user_tb u1_0 
            on u1_0.id=b1_0.user_id 
    where
        b1_0.id=?

 

JPQL์ด๋ž€?

  • JPQL์€ Java Persistence Query Language์˜ ์•ฝ์ž๋กœ, JPA์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด์ž…๋‹ˆ๋‹ค.
  • SQL๊ณผ ์œ ์‚ฌํ•˜์ง€๋งŒ, ํ…Œ์ด๋ธ”์ด ์•„๋‹Œ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • JPQL์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋…๋ฆฝ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์–ด, ํŠน์ • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฒค๋”์— ์ข…์†๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • JPQL์€ JPA ํ‘œ์ค€ ์ŠคํŽ™์˜ ์ผ๋ถ€๋กœ, ๋Œ€๋ถ€๋ถ„์˜ JPA ๊ตฌํ˜„์ฒด(Hibernate ๋“ฑ)์—์„œ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

 

JPQL - Fetch Join ํ™œ์šฉ (๊ฒŒ์‹œ๊ธ€ ์ƒ์„ธ ๋ณด๊ธฐ)

  • Fetch Join์ด๋ž€:
    • JPQL์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ํ•จ๊ป˜ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
    • ์ง€์—ฐ ๋กœ๋”ฉ ์„ค์ •๊ณผ ๊ด€๊ณ„์—†์ด ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฆ‰์‹œ ๋กœ๋”ฉํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ ์ด์œ 
    • N+1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฟผ๋ฆฌ ํšŸ์ˆ˜๋ฅผ ์ค„์ด๊ณ  ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ ๋ฐฉ๋ฒ•:
    • JPQL ์ฟผ๋ฆฌ์—์„œ JOIN FETCH ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.

 Fetch Join ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  • ๋ฐ์ดํ„ฐ ์ค‘๋ณต:
    • Fetch Join์œผ๋กœ ์—ฌ๋Ÿฌ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐ์ธํ•˜๋ฉด ๊ฒฐ๊ณผ๊ฐ€ ์ค‘๋ณต๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ•„์š”ํ•œ ์—”ํ‹ฐํ‹ฐ๋งŒ ์„ ํƒ์ ์œผ๋กœ ์กฐ์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํŽ˜์ด์ง• ์ œํ•œ:
    • JPA์—์„œ๋Š” Fetch Join์„ ์‚ฌ์šฉํ•œ ์ƒํƒœ์—์„œ ํŽ˜์ด์ง•์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
    • ๋ฐ์ดํ„ฐ๊ฐ€ ๋งŽ์„ ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ์ฆ๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ ์ ˆํ•œ ์‚ฌ์šฉ:
    • ๋ฌด๋ถ„๋ณ„ํ•œ ์‚ฌ์šฉ์€ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์„ ์ €ํ•˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

JPQL๊ณผ SQL์˜ ์ฐจ์ด์ 

  • JPQL์€ ๊ฐ์ฒด ์ง€ํ–ฅ ์ฟผ๋ฆฌ ์–ธ์–ด๋กœ, ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • SQL์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”๊ณผ ์ปฌ๋Ÿผ์„ ๋Œ€์ƒ์œผ๋กœ ์ฟผ๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
  • JPQL์€ ์—”ํ‹ฐํ‹ฐ์™€ ๊ทธ ์‚ฌ์ด์˜ ์—ฐ๊ด€ ๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋…๋ฆฝ์ ์ธ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

์šฐ๋ฆฌ๋Š” ์–ด๋–ค ์ „๋žต์„ ์„ ํƒํ•ด์•ผ ํ•˜๋‚˜?

  • ๊ธฐ๋ณธ์ ์œผ๋กœ Lazy Fetching์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ Fetch Join ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

 

์š”์•ฝ

  • Eager Fetching: ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ฆ‰์‹œ ๋กœ๋”ฉํ•˜์—ฌ, ์—”ํ‹ฐํ‹ฐ ์กฐํšŒ ์‹œ ํ•จ๊ป˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.
    • ์žฅ์ : ์—ฐ๊ด€๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ๋‹จ์ : ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋กœ๋”ฉ๋˜์–ด ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ๋‹ค.
  • Lazy Fetching: ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‹ค์ œ๋กœ ์ ‘๊ทผํ•  ๋•Œ๊นŒ์ง€ ๋กœ๋”ฉ์„ ์ง€์—ฐ์‹œํ‚ต๋‹ˆ๋‹ค.
    • ์žฅ์ : ํ•„์š”ํ•œ ์‹œ์ ์—๋งŒ ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ๋”ฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚จ๋‹ค.
    • ๋‹จ์ : ์ง€์—ฐ ๋กœ๋”ฉ ์‹œ์ ์— ์ถ”๊ฐ€์ ์ธ SQL ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
  • Fetch Join: ํ•œ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋กœ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ํ•จ๊ป˜ ๋กœ๋”ฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
    • ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ : ๋„ˆ๋ฌด ๋งŽ์ด ์‚ฌ์šฉํ•˜๋ฉด ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

 

Fetch ์ „๋žต ์„ ํƒ ๊ธฐ์ค€

  • Lazy Fetching์„ ๊ธฐ๋ณธ์œผ๋กœ ์‚ฌ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • Eager Fetching์€ ๋ฐ˜๋“œ์‹œ ํ•จ๊ป˜ ๋กœ๋”ฉํ•ด์•ผ ํ•˜๋Š” ์—ฐ๊ด€ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์„ ๋•Œ ์‹ ์ค‘ํžˆ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Fetch Join ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ

  • Fetch Join์€ ์ฆ‰์‹œ ๋กœ๋”ฉ๊ณผ ์œ ์‚ฌํ•˜๊ฒŒ ์ž‘๋™ํ•˜์ง€๋งŒ, ์›ํ•˜๋Š” ์‹œ์ ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ณต์žกํ•œ ์ฟผ๋ฆฌ๋‚˜ ๋ฐ์ดํ„ฐ ์–‘์ด ๋งŽ์€ ๊ฒฝ์šฐ ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ์ €ํ•˜๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์ฃผ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

N+1 ๋ฌธ์ œ

  • ์ง€์—ฐ ๋กœ๋”ฉ์„ ์‚ฌ์šฉํ•  ๋•Œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ฐ˜๋ณต์ ์œผ๋กœ ์กฐํšŒํ•˜๋ฉด, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋งŽ์€ ์ˆ˜์˜ SQL ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ด๋ฅผ N+1 ๋ฌธ์ œ๋ผ๊ณ  ํ•˜๋ฉฐ, Fetch Join ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.