์ค๋ ๋ธ๋ก๊ทธ์์ ์ฃผ๋ก ๋ค๋ฃฐ ๋ด์ฉ์ JPA์ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฌ์ฉํ ๋ ์กฐํ์ N + 1 ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ๋ค๋ฃฐ ์์ ์ด๋ค.
N + 1 ๋ฌธ์ ๋ ?
์ฟผ๋ฆฌ๋ฅผ 1๊ฐ๋ฅผ ์์ํ๊ณ ์ํ ํ์๋๋ฐ ์ถ๊ฐ ์ฟผ๋ฆฌ๊ฐ N๊ฐ ๋๊ฐ๋ค๋ ์๋ฏธ ์ ๋๋ค.
JPA์์ N + 1 ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ์ํด ํฌ๊ฒ @EntityGraph ์ Fetch Join ์ผ๋ก ํด๊ฒฐ ํ ์ ์์,
(๋๋ถ๋ถ Fetch Join ์ผ๋ก ํด๊ฒฐ)
(ํ์ง๋ง Fetch Join์ ํด๋ ๋ฌธ์ ๊ฐ ์กด์ฌ)
โก fetch Join์ ์ฌ์ฉํ๋ฉด Lazy ๋ฐฉ์์ ์ฌ์ฉํ ์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ๋ชจ๋ EAGER ๋ก๋ฉ ๋ฐฉ์์ผ๋ก ๊ฐ์ ธ์ต๋๋ค. (ํ์ํ์ง ์๋ ๋ฐ์ดํฐ๊น์ง ๋ชจ๋ ์กฐํ)
Product์ Image ์ฐ๊ด๊ด๊ณ (@OneToOne)
@Entity
public class Product {
@OneToOne(orphanRemoval = true)
@JoinColumn(name = "image_id")
private Image image;
}
๋ฌธ์ ์ ์ฝ๋ ์ด๋ค.
JPA์์๋.findAll()๋ฉ์๋๋ฅผ ์ ๊ณตํ์ฌ, ProductRepository์ ์ ์ฅ๋ ๋ฐ์ดํฐ๋ฅผ ๋ค ๊ธ์ด์ค๋ ๊ธฐ๋ฅ์ ํ๊ฒ ๋ฉ๋๋ค.
โ where ๋ฌธ์์ in ์ ๋ก Product ์ํฐํฐ์ ์ ์ฅ๋ Image ๊ฐ์ฒด ์ ์ฒด๋ฅผ ์กฐํ ํฉ๋๋ค.
(์ฑ๋ฅ์ ์ข์ง ์์) (ํํ findAll() ๋ฉ์๋ ์์ ๋ฐ์)
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 ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์๋ ์๋ต์๊ฐ์ ๋น๊ตํ ์์ ์ด๋ค.