JPA N+1 Problem

OneToMany(์ผ๋Œ€๋‹ค) ๋ฐ์ดํ„ฐ ์กฐํšŒ๋กœ ๋ณด๋Š” N+1

์‚ฌ์šฉ์ž, ๊ฒŒ์‹œ๋ฌผ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์กด์žฌํ•œ๋‹ค๊ณ  ํ•˜์ž. ํ•˜๋‚˜์˜ ์‚ฌ์šฉ์ž๋Š” ์—ฌ๋Ÿฌ ๊ฒŒ์‹œ๋ฌผ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ์‚ฌ์šฉ์ž-๊ฒŒ์‹œ๋ฌผ์€ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋ฅผ ๊ฐ–๋Š”๋‹ค.

์—ฌ๊ธฐ์„œ ๋ชจ๋“  ๊ฒŒ์‹œ๋ฌผ์„ ์กฐํšŒํ•˜๊ณ , ๊ฒŒ์‹œ๋ฌผ์„ ์ž‘์„ฑํ•œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฆ„๋„ ํ•จ๊ป˜ ์กฐํšŒํ•˜๋Š” ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ž‘์„ฑํ•œ๋‹ค๊ณ  ํ•˜์ž.

List<Post> postList = postRepository.findAll();

for (Post post: postList) {
		System.out.println("ํฌ์ŠคํŠธ๋ช…: " + post.getName());
		System.out.println("์ž‘์„ฑ์ž: " + post.getUser().getName());
		System.out.println("๋‚ด์šฉ: " + post.getContent());
}

์ด ๋กœ์ง์„ ์‹คํ–‰ํ•œ ํ›„ ์‹คํ–‰๋œ ์ฟผ๋ฆฌ๋“ค์„ ๋ณด๋ฉด, ์•„๋ž˜์™€ ๊ฐ™์€ ์ฟผ๋ฆฌ๋“ค์ด ์‹คํ–‰๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

๋ชจ๋“  ํฌ์ŠคํŠธ ์กฐํšŒ
ํฌ์ŠคํŠธ1์˜ ์‚ฌ์šฉ์ž ์กฐํšŒ
ํฌ์ŠคํŠธ2์˜ ์‚ฌ์šฉ์ž ์กฐํšŒ
...
ํฌ์ŠคํŠธN์˜ ์‚ฌ์šฉ์ž ์กฐํšŒ

์ฆ‰, 1๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋  ๊ฒƒ์„ ์˜ˆ์ƒํ•˜๊ณ  ์ž‘์„ฑํ•œ ๋กœ์ง์ž„์—๋„ N๊ฐœ ํฌ์ŠคํŠธ์˜ ์กฐํšŒ์— ๋Œ€ํ•ด N+1๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

N+1 Problem

  • N๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๊ธฐ ์œ„ํ•ด 1๋ฒˆ์˜ ์ฟผ๋ฆฌ๋งŒ ์‹คํ–‰๋  ๊ฒƒ์„ ๊ธฐ๋Œ€ํ–ˆ์œผ๋‚˜ **N๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐœ์ƒ**ํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ๋งํ•จ

  • JPA๋Š” ์ฟผ๋ฆฌ๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•ด์ฃผ๋Š” ํ”„๋ ˆ์ž„์›Œํฌ์ธ ๋งŒํผ ์ž˜ ๋ชจ๋ฅด๊ณ  ์“ฐ๋ฉด ์‹ฌ๊ฐํ•œ ๋น„ํšจ์œจ์„ฑ์„ ์ดˆ๋ž˜ํ•  ์ˆ˜ ์žˆ๊ณ , N+1 ๋ฌธ์ œ๋Š” ์ด ๋Œ€ํ‘œ์  ์‚ฌ๋ก€

์™œ ๋ฐœ์ƒํ•˜๋Š”๊ฐ€?

  • JPA๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์กฐํšŒ ์‹œ ์—ฐ๊ด€ ๊ด€๊ณ„์— ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋“ค์„ join์„ ํ†ตํ•ด ๊ฐ€์ ธ์˜ค๋Š” ๋Œ€์‹  ์ถ”๊ฐ€์  ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ด ๊ฐ€์ ธ์˜ฌ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•จ

    • ํ•œ ๋ฒˆ์— ๋‹ค ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์€ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„์ด๊ธฐ๋„ ํ•˜๊ณ , DB์™€ ๋‹ฌ๋ฆฌ ๊ฐ์ฒด๋Š” ์ฐธ์กฐ๋ผ๋Š” ๊ฒƒ์„ ๊ฐ€์ ธ ์–ธ์ œ๋“  ์—ฐ๊ด€๋œ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์กฐํšŒ ์‹œ์ ์„ ๋ฏธ๋ค„๋„ ์ƒ๊ด€ ์—†๊ธฐ ๋•Œ๋ฌธ์ธ ๋“ฏ

  • ๋”ฐ๋ผ์„œ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์กฐ์ธ ๋Œ€์‹  ๋ณ„๋„ ์กฐํšŒ๋กœ ํš๋“๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ

์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜๋Š”๊ฐ€?

1. fetch join์„ ํ†ตํ•œ ํ•ด๊ฒฐ

  • JPQL์—์„œ fetch join์„ ๋ช…์‹œํ•ด์ฃผ๋Š” ๋ฐฉ๋ฒ•

  • ๊ธฐ๋ณธ join์„ ์ด์šฉํ•ด๋„ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก๋˜๋Š” ๊ฒƒ์€ ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ ๋ฟ์ž„

  • fetch join์ž„์„ ๋ช…์‹œํ•ด์ฃผ๋ฉด join์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์™€ ์กฐํšŒํ•œ ์—”ํ‹ฐํ‹ฐ์™€ ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ(joinํ•œ ์—”ํ‹ฐํ‹ฐ) ๋ชจ๋‘ ์˜์†์„ฑ ์ปจํ…์ŠคํŠธ์— ๋“ฑ๋ก

  • ํ•˜์ง€๋งŒ fetch join์—๋Š” ์น˜๋ช…์  ๋ฌธ์ œ์ ์ด ์žˆ๋Š”๋ฐ, ๋ฐ์ดํ„ฐ๋ฅผ ์ผ๋ถ€๋งŒ ์กฐํšŒํ•ด์˜ค๋Š” ๊ฒƒ์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค๋Š” ๊ฒƒ

    • ์ฆ‰, SQL์˜ limit ๊ธฐ๋Šฅ์„ ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ

    • 10๋งŒ ๊ฐœ ๋ฐ์ดํ„ฐ๊ฐ€ ์žˆ์œผ๋ฉด ๋ชจ๋‘ ์กฐํšŒํ•ด์˜ค๋ฏ€๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ์น˜๋ช…์ 

2. @BatchSize๋ฅผ ํ†ตํ•œ N+1 ํ•ด๊ฒฐ

  • ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๋ฅผ in ์ ˆ์„ ํ†ตํ•ด ํ•˜๋‚˜๋กœ ๋ฌถ์–ด ์‹คํ–‰ํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•

  • ํ•ด๊ฒฐ์ด๋ผ๊ธฐ๋ณด๋‹ค๋Š” ์šฐํšŒ (๊ฒฐ๊ตญ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์ฟผ๋ฆฌ๊ฐ€ ๋ฐœ์ƒํ•  ์œ„ํ—˜์€ ์žˆ์œผ๋‚˜, ๊ทธ ์ˆ˜๋ฅผ batch size๊ฐ€ M์ด๋ผ๊ณ  ํ–ˆ์„ ๋•Œ N/M๊ฐœ ๋งŒํผ ์ค„์ด๋Š” ๊ฒƒ)

  • fetch join๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ผ๋ถ€๋งŒ ์กฐํšŒํ•ด์˜ค์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ ์กด์žฌ

3. @EntityGraph, @NamedEntityGraph

  • ์ฟผ๋ฆฌ ๋ฉ”์†Œ๋“œ์— ํ•จ๊ป˜ ์กฐํšŒํ•  ์—ฐ๊ด€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๋ช…์‹œํ•˜๋Š” ๋ฐฉ๋ฒ•

  • ํŽ˜์ด์ง•์ด(๋ฐ์ดํ„ฐ ์ผ๋ถ€ ์ ์žฌ๊ฐ€) ๊ฐ€๋Šฅํ•˜๊ณ , join์„ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ 1๊ฐœ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ ์•ž์„  ํ•ด๊ฒฐ์ฑ…๋“ค๋ณด๋‹ค๋Š” ๋ฌธ์ œ๊ฐ€ ์ ์–ด ๋ณด์ž„

  • ๊ทธ๋Ÿฌ๋‚˜ left outer join์„ ์ด์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์นดํ‹ฐ์‹œ์•ˆ ๊ณฑ์— ์˜ํ•ด ํ•˜๋‚˜์˜ ์—”ํ‹ฐํ‹ฐ๊ฐ€ ์—ฌ๋Ÿฌ ๋ฒˆ ์กฐํšŒ๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

    • ์ด๊ฑด fetch join ๋˜ํ•œ ๋งˆ์ฐฌ๊ฐ€์ง€

ํ˜„์žฌ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

๊ฒฐ๊ตญ ์œ„์˜ 1, 2, 3๋ฒˆ ํ•ด๊ฒฐ์ฑ… ๋ชจ๋‘ ๋‚˜๋ฆ„์˜ ๋ฌธ์ œ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์— ์–ด๋ ค์›€์ด ์žˆ์—ˆ๊ณ , ํ˜„์žฌ์—๋Š” QueryDSL์„ ์ด์šฉํ•˜์—ฌ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์žˆ๋‹ค.

JPQL ๋ ˆ๋ฒจ์—์„œ ์ด ๋ฌธ์ œ๋ฅผ ๊น”๋”ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ์ฟผ๋ฆฌ๊ฐ€ ๋ณต์žกํ•ด์ง€๊ณ , ๋ณต์žกํ•œ ๋ฌธ์ž์—ด ์ฟผ๋ฆฌ๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ๊ธฐ๋ฉด ๋ณ€๊ฒฝ๊ณผ ํ™•์žฅ์ด ์–ด๋ ค์›Œ์ ธ ์œ ์ง€๋ณด์ˆ˜์— ์šฉ์ดํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ๊ฐ€ ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ถœ์ฒ˜

https://bcp0109.tistory.com/304

https://cobbybb.tistory.com/18

Last updated