๋ฉ‹์‚ฌ Backend Plus 41์ผ์ฐจ ๐Ÿฆ

์‹ ์žฌ์›ยท2023๋…„ 12์›” 26์ผ

์˜ค๋Š˜ ๋ธ”๋กœ๊ทธ์—์„œ ์ฃผ๋กœ ๋‹ค๋ฃฐ ๋‚ด์šฉ์€ JPA์˜ ์—ฐ๊ด€๊ด€๊ณ„๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์กฐํšŒ์‹œ N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค.

N + 1 ๋ฌธ์ œ ์›์ธ

N + 1 ๋ฌธ์ œ๋ž€ ?

์ฟผ๋ฆฌ๋ฅผ 1๊ฐœ๋ฅผ ์˜ˆ์ƒํ•˜๊ณ  ์ˆ˜ํ–‰ ํ•˜์˜€๋Š”๋ฐ ์ถ”๊ฐ€ ์ฟผ๋ฆฌ๊ฐ€ N๊ฐœ ๋‚˜๊ฐ„๋‹ค๋Š” ์˜๋ฏธ ์ž…๋‹ˆ๋‹ค.

JPA์—์„œ N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ์œ„ํ•ด ํฌ๊ฒŒ @EntityGraph ์™€ Fetch Join ์œผ๋กœ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์Œ,
(๋Œ€๋ถ€๋ถ„ Fetch Join ์œผ๋กœ ํ•ด๊ฒฐ)
(ํ•˜์ง€๋งŒ Fetch Join์„ ํ•ด๋„ ๋ฌธ์ œ๊ฐ€ ์กด์žฌ)

โžก fetch Join์„ ์‚ฌ์šฉํ•˜๋ฉด Lazy ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ชจ๋‘ EAGER ๋กœ๋”ฉ ๋ฐฉ์‹์œผ๋กœ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. (ํ•„์š”ํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๋ชจ๋‘ ์กฐํšŒ)


N + 1 ๋ฌธ์ œ ์˜ˆ์‹œ

Product์™€ Image ์—ฐ๊ด€๊ด€๊ณ„ (@OneToOne)

@Entity
public class Product {
    @OneToOne(orphanRemoval = true)
    @JoinColumn(name = "image_id")
    private Image image;
}

๋ฌธ์ œ์˜ ์ฝ”๋“œ ์ด๋‹ค.
JPA ์—์„œ๋Š” .findAll() ๋ฉ”์†Œ๋“œ๋ฅผ ์ œ๊ณตํ•˜์—ฌ, ProductRepository์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค ๊ธ์–ด์˜ค๋Š” ๊ธฐ๋Šฅ์„ ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

SQL ์ฟผ๋ฆฌ ๊ฒฐ๊ณผ

โ†’ where ๋ฌธ์—์„œ in ์ ˆ๋กœ Product ์—”ํ‹ฐํ‹ฐ์— ์ €์žฅ๋œ Image ๊ฐ์ฒด ์ „์ฒด๋ฅผ ์กฐํšŒ ํ•ฉ๋‹ˆ๋‹ค.
(์„ฑ๋Šฅ์ƒ ์ข‹์ง€ ์•Š์Œ) (ํ”ํžˆ findAll() ๋ฉ”์†Œ๋“œ ์—์„œ ๋ฐœ์ƒ)

N + 1 ๋ฌธ์ œ ํ•ด๊ฒฐ

fetch join ์‚ฌ์šฉ

ProductRepository์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด join fetch ์ฟผ๋ฆฌ๋ฌธ์„ ์ž‘์„ฑํ•˜์—ฌ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

public interface ProductRepository extends JpaRepository<Product, Long> {

    @Query("select p from Product p join fetch p.image order by p.id desc")
    List<Product> findAllWithImage();
}

์ „์ฒด ์ƒํ’ˆ ์กฐํšŒ์‹œ ์ฟผ๋ฆฌ ํ•œ๋ฐฉ์œผ๋กœ ํ•ด๊ฒฐํ•˜์—ฌ ์‘๋‹ต ์‹œ๊ฐ„์„ ๊ฐœ์„  ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

์•„๋ž˜์˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ, @Param ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ JPQL ์„ ์ž‘์„ฑ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

@Query("select p from Product p join fetch p.image 
					where p.productName = :productName")
List<Product> findByProductName(@Param("productName") String productName);

๋งˆ๋ฌด๋ฆฌ

fetch join์ด ์•„๋‹Œ EntityGraph ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•ด์„œ N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐ ํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ๋” ๊ณต๋ถ€๋ฅผ ํ•ด์•ผ ๋  ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€๋กœ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋˜๋ฉด ์‘๋‹ต์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฐ๋‹ค๋Š” ์ถ”์ƒ์ ์ธ ๊ฐœ๋…๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ์–ด,
ํ”„๋กœ์ ํŠธ๋ฅผ ๋””๋ฒจ๋กญ ํ•˜๋ฉด์„œ N + 1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„๋–„์˜ ์‘๋‹ต์‹œ๊ฐ„๊ณผ N + 1 ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์„๋•Œ ์‘๋‹ต์‹œ๊ฐ„์„ ๋น„๊ตํ•  ์˜ˆ์ •์ด๋‹ค.

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