๋ฌธ์ ๐ฟ
ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ํ๊ธฐ ์ํด ํน์ API์ ๋ํ์ฌ ํ ๋ฒ์ ๋ง์ ์์ฒญ์ ๋ณด๋๊ณ , ํ์์ ์ ๋์ํ๋ API๊ฐ OutOfMemoryError๋ฅผ ๋์ง๋ฉด์ ๋ชจ๋ ์์ฒญ์ ๋ํด ์คํจํ์๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ด๋ค ๊ณผ์ ์ ๊ฑฐ์ณค๋์ง ์์ธํ ์ดํด๋ณด์ ๐ง
์ผ๋จ ๊ฒฐ๋ก ๋ถํฐ..
๊ทธ ์ ์ ๊ธ์ด ๊ธธ์ด์ง ๊ฒ ๊ฐ์ผ๋ฏ๋ก ๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด,
1:N ์ฐ๊ด๊ด๊ณ์์ fetchJoin๊ณผ limit ๊ตฌ๋ฌธ์ ํจ๊ป ์ฐ๋ฉด ์ํํ๋ค!
๋ฌธ์ ์ํฉ
ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ํ๊ธฐ ์ํด Jmeter๋ฅผ ์ฌ์ฉํ์๊ณ , 1์ด์ 500๋ฒ์ ๋ก๋๋งต ๋ชฉ๋ก ์กฐํ ์์ฒญ์ ๋ณด๋ด๋๋ก ์ค์ ํ๋ค.
๊ทธ๋ฐ๋ฐ 500๋ฒ์ ์์ฒญ์ด ๋ชจ๋ ์คํจํ๊ณ , ์ด๋ค ์๋ฌ ๋ฉ์ธ์ง๊ฐ ๋ด๊ฒจ์๋์ง ํ์ธํ๋ค.
๋ฉ์ธ์ง๋ ๋ค์๊ณผ ๊ฐ์๋ค.
"Handler dispatch failed: java.lang.OutOfMemoryError: Java heap space"
์์๋ ๋ชปํ OutOfMemoryError๊ฐ ๋ฐ์ํ๋ค. ์ด์ ์๋ ํ ๋ฒ๋ ๋ง๋๋ณด์ง ๋ชปํ๋ ์๋ฌ์๋ค.
๋ฐ๋ก ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ก๊ทธ๋ฅผ ํ์ธํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ๊ณ ๊ฐ ๋ ์๋ ๊ฒ์ ๋ฐ๊ฒฌํ ์ ์์๋ค.
[WARN] [http-nio-9000-exec-483] [org.hibernate.orm.query] - HHH90003004:
firstResult/maxResults specified with collection fetch; applying in memory
๋ฐ๋ก ์ฐ๋ฆฌ์ ์ฟผ๋ฆฌ์ ๋ฌธ์ ๊ฐ ์์๋ค๋ ๊ฒ์ ์๊ฒ๋์๋ค. (๊ฒฝ๊ณ ๋ฅผ ์ฃผ๊ณ ์๋ค๋ ๊ฒ ์กฐ์ฐจ ๋ชจ๋ฅด๊ณ ์์๋ค ๐ )
๊ทธ๋ผ ๋ก๋๋งต ๋ชฉ๋ก ์กฐํ ์์ฒญ ๋ ์ฌ์ฉํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ดํด๋ณด์!
์ํฐํฐ ์ฐ๊ด๊ด๊ณ
๊ทธ ์ ์ ์ดํด๋ฅผ ๋๊ธฐ ์ํด ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ์ ๋ํด์ ๊ฐ๋จํ๊ฒ ์ค๋ช ํ๋ฉด
- '๋ก๋๋งต'๊ณผ '๋ก๋๋งต ํ๊ทธ'๋ผ๋ ์ํฐํฐ๋ 1:N ๊ด๊ณ์ด๋ค.
- ํ '๋ก๋๋งต'์ ๋ํ์ฌ '๋ก๋๋งต ํ๊ทธ'๋ ์ต์ 1๊ฐ๋ถํฐ ์ต๋ 5๊ฐ๊น์ง ์กด์ฌํ ์ ์๋ค.

๋ฌธ์ ์ ์ฟผ๋ฆฌ ๐
๋ฌดํ ์คํฌ๋กค์ ์ํด ๋ก๋๋งต ๋ชฉ๋ก์ ๊ฐ์ ธ์ฌ ๋ ์์ฒญ๋ฐ์ ์ฌ์ด์ฆ๋งํผ ๋ก๋๋งต์ ์ ๋ฌํ๋๋ฐ, ์ด๋ ๋ก๋๋งต๊ณผ ๋ก๋๋งต ํ๊ทธ๋ฅผ ๋ชจ๋ ๋ฐํํ๋ค.
๋ก๋๋งต ํ๊ทธ๋ ์ง์ฐ ๋ก๋ฉ์ผ๋ก ์ค์ ํด๋์๊ธฐ ๋๋ฌธ์, N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด fetchJoin์ ๋ถ์ฌ ํ ๋ฒ์ ๊ฐ์ ธ์ค๋๋ก ํ๋ค.
๋ค์์ ์ค์ QueryDsl๋ก ์์ฑํ ์ฟผ๋ฆฌ๋ฌธ์ด๋ค.

๋ก๋๋งต ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด leftJoin๊ณผ fetchJoin์ ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์์ฒญ๋ฐ์ ์ฌ์ด์ฆ๋งํผ ๋ก๋๋งต์ ์กฐํํ๊ธฐ ์ํด limit ๊ตฌ๋ฌธ์ ์ถ๊ฐํ๋ค.
๊ทธ๋ฐ๋ฐ.
์ค์ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ ๊ฒ์ ํ์ธํด๋ณด๋ limit ๊ตฌ๋ฌธ์ด ์ ์ฉ์ด ๋์ง ์๊ณ ์์๋ค.
select
--...
from
roadmap r1_0
--...
left join
roadmap_tag v1_0
on r1_0.id=v1_0.roadmap_id
where
r1_0.status=?
order by
r1_0.created_at desc
์ด์
๊ทธ ์ด์ ๋ fetchJoin๊ณผ limit์ ํจ๊ป ์จ์ ๊ทธ๋ ๋ค.
N์ชฝ์ ํ ์ด๋ธ์์ ๋ช ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผํ๋์ง ์ ์ ์์ด์ ํ ์ด๋ธ ์ ๋ณด๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ฌ ์ ๋ฐ์ ์๋ค๋ ๊ฒ์ด๋ค.
์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋ก๋๋งต์ด ์กด์ฌํ๋ค๊ณ ํ์.
์ฐ๋ฆฌ๋ ๋ก๋๋งต 3๊ฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด limit 3์ ๊ฑธ์๋ค.
์ฐ์ ๋ก๋๋งต ํ๊ทธ์ fetchJoin์ ๋ถ์ด์ง ์์ผ๋ฉด ์ด๋ค ๊ฒฐ๊ณผ๊ฐ ๋์ฌ๊น?

๊ฒฐ๊ณผ๋ ๋ก๋๋งต1๋ฐ์ ๊ฐ์ ธ์ค์ง ๋ชปํ๋ค.
๊ทธ ์ด์ ๋ ๋ก๋๋งต๊ณผ ๋ก๋๋งต ํ๊ทธ๋ฅผ Join ํ๊ธฐ ๋๋ฌธ์,
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-1)
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-2)
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-3)
์ด๋ ๊ฒ 3๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์กฐํ๋์๊ณ , ์ํฐํฐ๋ก ๋ณํ๋๋ฉด์ ๋ก๋๋งต 1๊ฐ๋ง ๋ฐํ๋๋ ๊ฒ์ด๋ค.
๐ฎ.. ์ฐ๋ฆฌ๊ฐ ์์ํ๋ ๊ฒฐ๊ณผ๊ฐ์ ์ ํ ๋ฐ์ง ๋ชปํ๊ณ ์๋ค.
๊ทธ๋์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด fetchJoin์ ์ฌ์ฉํด์ ์ํ๋๋๋ก ๋ก๋๋งต 3๊ฐ๋ฅผ ๋ฐ์์ง๋ง,
์์ ๋งํ๋ limit ๊ตฌ๋ฌธ์ด ์ ์ฉ๋์ง ์๋ ๋ฌธ์ ๊ฐ ์๊ฒผ๋ค.
๋ก๋๋งต ํ๊ทธ ํ ์ด๋ธ์ ๋ชจ๋ ๊ฐ์ ธ์ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค๋๊ณ ์ดํ๋ฆฌ์ผ์ด์ ๋จ์์ limit ๋งํผ ์๋ฅด๊ธฐ ๋๋ฌธ์,
์์ฒญ์ ํ ๋ฒ์ ๋ง์ด ๋ณด๋์ ๋ Out of Memory ๋ฌธ์ ๊ฐ ์๊ฒผ๋ ๊ฒ์ด๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ ๐ก
์ฟผ๋ฆฌ๋ฅผ ํ ๋ฒ๋ง ๋ณด๋ด์ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค์๋ ์์ฌ์ ๋ฒ๋ฆฌ๊ณ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฒ ๋ ๋ฆฌ๋๋ก ์์ ํ๋ค.
1. ๋ก๋๋งต์ ์ง์ ๋ ์ฌ์ด์ฆ ๋งํผ ์กฐํํ๋ ์ฟผ๋ฆฌ (๋ก๋๋งต ํ๊ทธ ์ ์ธํ๊ณ ์กฐํ)
2. ์กฐํํ ๋ก๋๋งต์ ํ๊ทธ๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ
๊ทธ๋ฆฌ๊ณ ๋ก๋๋งต ํ๊ทธ๋ฅผ ์กฐํํ ๋, ํ๊ทธ ๊ฐ์์ ๋ฐ๋ผ n+1๋ฒ ์กฐํํ์ง ์๊ธฐ ์ํด @BatchSize๋ผ๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ์๋ค.
์ด ์ด๋ ธํ ์ด์ ์ ๋ถ์ด๋ฉด ์ง์ ํ size๋งํผ In์ ์ ์ด์ฉํด selectํ ์ ์๋ค.
๋ก๋๋งต ์ํฐํฐ์ ๋ก๋๋งต ํ๊ทธ ํ๋์ @BatchSize๋ฅผ ์ ์ฉํ๋ค.
@Entity
public class Roadmap {
private Long id;
@OneToMany(fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE},
orphanRemoval = true)
@JoinColumn(name = "roadmap_id", updatable = false, nullable = false)
@BatchSize(size = 20) // here!!! ๐ก
private final Set<RoadmapTag> values = new HashSet<>();
// ...
}
๋ก๋๋งต์ ์กฐํํ ๋ 20๊ฐ๋ณด๋ค ๋๊ฒ ์กฐํํ ์ผ์ด ์๊ธฐ ๋๋ฌธ์ ์ ์ ํ๊ฒ ์ฌ์ด์ฆ๋ฅผ 20์ผ๋ก ์ง์ ํด์ฃผ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ์ ๋๋ก ๋๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๊ธฐ์กด ์ฟผ๋ฆฌ์ ๋ค๋ฅธ ์ ์ ์ฒซ๋ฒ์งธ ์ฟผ๋ฆฌ์์๋ ๋ก๋๋งต ํ๊ทธ๋ฅผ ์กฐํํ์ง ์๋๋ค. ๋ฐ๋ผ์ limit ์ ์ด ์ ๋๋ก ์ ์ฉ๋์๋ค.

์ดํ ๋๋ฒ์งธ ์ฟผ๋ฆฌ์์๋, ์์ ์กฐํํ ๋ก๋๋งต์ ๊ฐ๊ฐ์ ํ๊ทธ๋ฅผ ์กฐํํ๋ ๋ฐ, ์ด๋ In์ ์ ์ด์ฉํ์ฌ ํ๋ฒ์ ์ฟผ๋ฆฌ๋ก ๋ชจ๋ ๋ก๋๋งต์ ํ๊ทธ๋ฅผ ์กฐํํ์๋ค.

์ดํ ๋์ผํ ์ํฉ์ผ๋ก ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ๋ค์ ์๋ํด๋ณด์๊ณ ๋ชจ๋ ์ฑ๊ณตํ๋ค. ๐
๊ฒฐ๋ก ๐ฌ
1:N ์ฐ๊ด๊ด๊ณ์์ fetchJoin๊ณผ Limit ๊ตฌ๋ฌธ์ ํจ๊ป ์ฐ์ง ์๋๋ก ์กฐ์ฌํ์.
๋ N+1 ๋ฌธ์ ๋ฅผ ํผํ๊ธฐ ์ํด ๋ฌด์์ fetchJoin์ ๋ถ์ด์ง๋ง๊ณ ์ ์คํ๊ฒ ํ์.
์ค์ ์ฟผ๋ฆฌ๊ฐ ์ด๋ป๊ฒ ๋๊ฐ๋์ง๋ ๊ผญ ํ์ธํ๋ ๊ฒ์ด ํ์ํ ๊ฒ ๊ฐ๋ค!
๋ฌธ์ ๐ฟ
ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ํ๊ธฐ ์ํด ํน์ API์ ๋ํ์ฌ ํ ๋ฒ์ ๋ง์ ์์ฒญ์ ๋ณด๋๊ณ , ํ์์ ์ ๋์ํ๋ API๊ฐ OutOfMemoryError๋ฅผ ๋์ง๋ฉด์ ๋ชจ๋ ์์ฒญ์ ๋ํด ์คํจํ์๋ค.
์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ด๋ค ๊ณผ์ ์ ๊ฑฐ์ณค๋์ง ์์ธํ ์ดํด๋ณด์ ๐ง
์ผ๋จ ๊ฒฐ๋ก ๋ถํฐ..
๊ทธ ์ ์ ๊ธ์ด ๊ธธ์ด์ง ๊ฒ ๊ฐ์ผ๋ฏ๋ก ๊ฒฐ๋ก ๋ถํฐ ๋งํ์๋ฉด,
1:N ์ฐ๊ด๊ด๊ณ์์ fetchJoin๊ณผ limit ๊ตฌ๋ฌธ์ ํจ๊ป ์ฐ๋ฉด ์ํํ๋ค!
๋ฌธ์ ์ํฉ
ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ํ๊ธฐ ์ํด Jmeter๋ฅผ ์ฌ์ฉํ์๊ณ , 1์ด์ 500๋ฒ์ ๋ก๋๋งต ๋ชฉ๋ก ์กฐํ ์์ฒญ์ ๋ณด๋ด๋๋ก ์ค์ ํ๋ค.
๊ทธ๋ฐ๋ฐ 500๋ฒ์ ์์ฒญ์ด ๋ชจ๋ ์คํจํ๊ณ , ์ด๋ค ์๋ฌ ๋ฉ์ธ์ง๊ฐ ๋ด๊ฒจ์๋์ง ํ์ธํ๋ค.
๋ฉ์ธ์ง๋ ๋ค์๊ณผ ๊ฐ์๋ค.
"Handler dispatch failed: java.lang.OutOfMemoryError: Java heap space"
์์๋ ๋ชปํ OutOfMemoryError๊ฐ ๋ฐ์ํ๋ค. ์ด์ ์๋ ํ ๋ฒ๋ ๋ง๋๋ณด์ง ๋ชปํ๋ ์๋ฌ์๋ค.
๋ฐ๋ก ์ดํ๋ฆฌ์ผ์ด์ ์ ๋ก๊ทธ๋ฅผ ํ์ธํ๋ค.
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ๊ณ ๊ฐ ๋ ์๋ ๊ฒ์ ๋ฐ๊ฒฌํ ์ ์์๋ค.
[WARN] [http-nio-9000-exec-483] [org.hibernate.orm.query] - HHH90003004:
firstResult/maxResults specified with collection fetch; applying in memory
๋ฐ๋ก ์ฐ๋ฆฌ์ ์ฟผ๋ฆฌ์ ๋ฌธ์ ๊ฐ ์์๋ค๋ ๊ฒ์ ์๊ฒ๋์๋ค. (๊ฒฝ๊ณ ๋ฅผ ์ฃผ๊ณ ์๋ค๋ ๊ฒ ์กฐ์ฐจ ๋ชจ๋ฅด๊ณ ์์๋ค ๐ )
๊ทธ๋ผ ๋ก๋๋งต ๋ชฉ๋ก ์กฐํ ์์ฒญ ๋ ์ฌ์ฉํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ดํด๋ณด์!
์ํฐํฐ ์ฐ๊ด๊ด๊ณ
๊ทธ ์ ์ ์ดํด๋ฅผ ๋๊ธฐ ์ํด ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ์ ๋ํด์ ๊ฐ๋จํ๊ฒ ์ค๋ช ํ๋ฉด
- '๋ก๋๋งต'๊ณผ '๋ก๋๋งต ํ๊ทธ'๋ผ๋ ์ํฐํฐ๋ 1:N ๊ด๊ณ์ด๋ค.
- ํ '๋ก๋๋งต'์ ๋ํ์ฌ '๋ก๋๋งต ํ๊ทธ'๋ ์ต์ 1๊ฐ๋ถํฐ ์ต๋ 5๊ฐ๊น์ง ์กด์ฌํ ์ ์๋ค.

๋ฌธ์ ์ ์ฟผ๋ฆฌ ๐
๋ฌดํ ์คํฌ๋กค์ ์ํด ๋ก๋๋งต ๋ชฉ๋ก์ ๊ฐ์ ธ์ฌ ๋ ์์ฒญ๋ฐ์ ์ฌ์ด์ฆ๋งํผ ๋ก๋๋งต์ ์ ๋ฌํ๋๋ฐ, ์ด๋ ๋ก๋๋งต๊ณผ ๋ก๋๋งต ํ๊ทธ๋ฅผ ๋ชจ๋ ๋ฐํํ๋ค.
๋ก๋๋งต ํ๊ทธ๋ ์ง์ฐ ๋ก๋ฉ์ผ๋ก ์ค์ ํด๋์๊ธฐ ๋๋ฌธ์, N+1 ๋ฌธ์ ๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด fetchJoin์ ๋ถ์ฌ ํ ๋ฒ์ ๊ฐ์ ธ์ค๋๋ก ํ๋ค.
๋ค์์ ์ค์ QueryDsl๋ก ์์ฑํ ์ฟผ๋ฆฌ๋ฌธ์ด๋ค.

๋ก๋๋งต ํ๊ทธ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด leftJoin๊ณผ fetchJoin์ ํ ๊ฒ์ ํ์ธํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ ์์ฒญ๋ฐ์ ์ฌ์ด์ฆ๋งํผ ๋ก๋๋งต์ ์กฐํํ๊ธฐ ์ํด limit ๊ตฌ๋ฌธ์ ์ถ๊ฐํ๋ค.
๊ทธ๋ฐ๋ฐ.
์ค์ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ ๊ฒ์ ํ์ธํด๋ณด๋ limit ๊ตฌ๋ฌธ์ด ์ ์ฉ์ด ๋์ง ์๊ณ ์์๋ค.
select
--...
from
roadmap r1_0
--...
left join
roadmap_tag v1_0
on r1_0.id=v1_0.roadmap_id
where
r1_0.status=?
order by
r1_0.created_at desc
์ด์
๊ทธ ์ด์ ๋ fetchJoin๊ณผ limit์ ํจ๊ป ์จ์ ๊ทธ๋ ๋ค.
N์ชฝ์ ํ ์ด๋ธ์์ ๋ช ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์์ผํ๋์ง ์ ์ ์์ด์ ํ ์ด๋ธ ์ ๋ณด๋ฅผ ๋ชจ๋ ๊ฐ์ ธ์ฌ ์ ๋ฐ์ ์๋ค๋ ๊ฒ์ด๋ค.
์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ด ๋ก๋๋งต์ด ์กด์ฌํ๋ค๊ณ ํ์.
์ฐ๋ฆฌ๋ ๋ก๋๋งต 3๊ฐ๋ฅผ ๊ฐ์ ธ์ค๊ธฐ ์ํด limit 3์ ๊ฑธ์๋ค.
์ฐ์ ๋ก๋๋งต ํ๊ทธ์ fetchJoin์ ๋ถ์ด์ง ์์ผ๋ฉด ์ด๋ค ๊ฒฐ๊ณผ๊ฐ ๋์ฌ๊น?

๊ฒฐ๊ณผ๋ ๋ก๋๋งต1๋ฐ์ ๊ฐ์ ธ์ค์ง ๋ชปํ๋ค.
๊ทธ ์ด์ ๋ ๋ก๋๋งต๊ณผ ๋ก๋๋งต ํ๊ทธ๋ฅผ Join ํ๊ธฐ ๋๋ฌธ์,
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-1)
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-2)
- (๋ก๋๋งต1, ๋ก๋๋งต ํ๊ทธ1-3)
์ด๋ ๊ฒ 3๊ฐ์ ๋ฐ์ดํฐ๊ฐ ์กฐํ๋์๊ณ , ์ํฐํฐ๋ก ๋ณํ๋๋ฉด์ ๋ก๋๋งต 1๊ฐ๋ง ๋ฐํ๋๋ ๊ฒ์ด๋ค.
๐ฎ.. ์ฐ๋ฆฌ๊ฐ ์์ํ๋ ๊ฒฐ๊ณผ๊ฐ์ ์ ํ ๋ฐ์ง ๋ชปํ๊ณ ์๋ค.
๊ทธ๋์ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด fetchJoin์ ์ฌ์ฉํด์ ์ํ๋๋๋ก ๋ก๋๋งต 3๊ฐ๋ฅผ ๋ฐ์์ง๋ง,
์์ ๋งํ๋ limit ๊ตฌ๋ฌธ์ด ์ ์ฉ๋์ง ์๋ ๋ฌธ์ ๊ฐ ์๊ฒผ๋ค.
๋ก๋๋งต ํ๊ทธ ํ ์ด๋ธ์ ๋ชจ๋ ๊ฐ์ ธ์ ๋ฉ๋ชจ๋ฆฌ์ ์ฌ๋ ค๋๊ณ ์ดํ๋ฆฌ์ผ์ด์ ๋จ์์ limit ๋งํผ ์๋ฅด๊ธฐ ๋๋ฌธ์,
์์ฒญ์ ํ ๋ฒ์ ๋ง์ด ๋ณด๋์ ๋ Out of Memory ๋ฌธ์ ๊ฐ ์๊ฒผ๋ ๊ฒ์ด๋ค.
ํด๊ฒฐ๋ฐฉ๋ฒ ๐ก
์ฟผ๋ฆฌ๋ฅผ ํ ๋ฒ๋ง ๋ณด๋ด์ ๋ชจ๋ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค์๋ ์์ฌ์ ๋ฒ๋ฆฌ๊ณ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฒ ๋ ๋ฆฌ๋๋ก ์์ ํ๋ค.
1. ๋ก๋๋งต์ ์ง์ ๋ ์ฌ์ด์ฆ ๋งํผ ์กฐํํ๋ ์ฟผ๋ฆฌ (๋ก๋๋งต ํ๊ทธ ์ ์ธํ๊ณ ์กฐํ)
2. ์กฐํํ ๋ก๋๋งต์ ํ๊ทธ๋ฅผ ์กฐํํ๋ ์ฟผ๋ฆฌ
๊ทธ๋ฆฌ๊ณ ๋ก๋๋งต ํ๊ทธ๋ฅผ ์กฐํํ ๋, ํ๊ทธ ๊ฐ์์ ๋ฐ๋ผ n+1๋ฒ ์กฐํํ์ง ์๊ธฐ ์ํด @BatchSize๋ผ๋ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ์๋ค.
์ด ์ด๋ ธํ ์ด์ ์ ๋ถ์ด๋ฉด ์ง์ ํ size๋งํผ In์ ์ ์ด์ฉํด selectํ ์ ์๋ค.
๋ก๋๋งต ์ํฐํฐ์ ๋ก๋๋งต ํ๊ทธ ํ๋์ @BatchSize๋ฅผ ์ ์ฉํ๋ค.
@Entity
public class Roadmap {
private Long id;
@OneToMany(fetch = FetchType.LAZY,
cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE},
orphanRemoval = true)
@JoinColumn(name = "roadmap_id", updatable = false, nullable = false)
@BatchSize(size = 20) // here!!! ๐ก
private final Set<RoadmapTag> values = new HashSet<>();
// ...
}
๋ก๋๋งต์ ์กฐํํ ๋ 20๊ฐ๋ณด๋ค ๋๊ฒ ์กฐํํ ์ผ์ด ์๊ธฐ ๋๋ฌธ์ ์ ์ ํ๊ฒ ์ฌ์ด์ฆ๋ฅผ 20์ผ๋ก ์ง์ ํด์ฃผ์๋ค.
๋ค์๊ณผ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ ์ ๋๋ก ๋๊ฐ๋ ๊ฒ์ ํ์ธํ ์ ์์๋ค.
๊ธฐ์กด ์ฟผ๋ฆฌ์ ๋ค๋ฅธ ์ ์ ์ฒซ๋ฒ์งธ ์ฟผ๋ฆฌ์์๋ ๋ก๋๋งต ํ๊ทธ๋ฅผ ์กฐํํ์ง ์๋๋ค. ๋ฐ๋ผ์ limit ์ ์ด ์ ๋๋ก ์ ์ฉ๋์๋ค.

์ดํ ๋๋ฒ์งธ ์ฟผ๋ฆฌ์์๋, ์์ ์กฐํํ ๋ก๋๋งต์ ๊ฐ๊ฐ์ ํ๊ทธ๋ฅผ ์กฐํํ๋ ๋ฐ, ์ด๋ In์ ์ ์ด์ฉํ์ฌ ํ๋ฒ์ ์ฟผ๋ฆฌ๋ก ๋ชจ๋ ๋ก๋๋งต์ ํ๊ทธ๋ฅผ ์กฐํํ์๋ค.

์ดํ ๋์ผํ ์ํฉ์ผ๋ก ํฐ์บฃ ์ฑ๋ฅํ ์คํธ๋ฅผ ๋ค์ ์๋ํด๋ณด์๊ณ ๋ชจ๋ ์ฑ๊ณตํ๋ค. ๐
๊ฒฐ๋ก ๐ฌ
1:N ์ฐ๊ด๊ด๊ณ์์ fetchJoin๊ณผ Limit ๊ตฌ๋ฌธ์ ํจ๊ป ์ฐ์ง ์๋๋ก ์กฐ์ฌํ์.
๋ N+1 ๋ฌธ์ ๋ฅผ ํผํ๊ธฐ ์ํด ๋ฌด์์ fetchJoin์ ๋ถ์ด์ง๋ง๊ณ ์ ์คํ๊ฒ ํ์.
์ค์ ์ฟผ๋ฆฌ๊ฐ ์ด๋ป๊ฒ ๋๊ฐ๋์ง๋ ๊ผญ ํ์ธํ๋ ๊ฒ์ด ํ์ํ ๊ฒ ๊ฐ๋ค!