Spring

[Spring] N+1 ๋ฌธ์ œ์™€ fetch join ํ•ด๊ฒฐ ๋ฐ ํ…Œ์ŠคํŠธ

DAHLIA CHOI 2024. 3. 15. 22:44

 

 

๐ŸŒฑ N+1 ๋ฌธ์ œ๋ž€?

JPA ์—ฐ๊ด€๊ด€๊ณ„์—์„œ ์ƒ๊ธฐ๋Š” ์ด์Šˆ๋กœ ์—ฐ๊ด€ ๊ด€๊ณ„๊ฐ€ ์„ค์ •๋œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•  ๊ฒฝ์šฐ ์กฐํšŒ๋œ ๋ฐ์ดํ„ฐ ๊ฐœ์ˆ˜(N)๋งŒํผ ์—ฐ๊ด€ ๊ด€๊ณ„์˜ ์กฐํšŒ ์ฟผ๋ฆฌ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋ฐœ์ƒํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ๋ฌธ์ œ๋ฅผ ๋งํ•œ๋‹ค.

 

 

๐Ÿค” ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•ด์•ผ ํ• ๊นŒ?

1. Fetch Type์„ Lazy๋กœ ์„ค์ •ํ•œ๋‹ค.

2. fetch join์„ ์‚ฌ์šฉํ•œ๋‹ค.

3. Batch Size๋ฅผ ์กฐ์ ˆํ•œ๋‹ค.

 

์—ฌ๊ธฐ์„œ ๋‚œ 1, 2๋ฒˆ์„ ๊ฐ€์ง€๊ณ  ํ•ด๊ฒฐํ•ด ๋ณด์•˜๋‹ค.

 

 

๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป ํ•ด๊ฒฐ ๊ณผ์ • ๋ฐ ํ…Œ์ŠคํŠธ

๋‚˜๋Š” ์ด ํ”„๋กœ์ ํŠธ์—์„œ ๋ชจ๋“  ์œ ์ € ๊ฐ์ฒด์— ๋Œ€ํ•ด์„œ ๊ธ€ ์ •๋ณด์™€ ๊ฐ™์ด ๋งคํ•‘ํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜์˜€๋‹ค.

Member ๊ฐ์ฒด์™€์˜ fetch type์„ Lazy๋กœ ์„ค์ •ํ•˜์˜€๋‹ค.

 

ํ•˜์ง€๋งŒ ์ด๋ ‡๊ฒŒ๋งŒ ๋ถ™์ธ๋‹ค๊ณ  ํ•ด์„œ ํ•ด๊ฒฐ์ด ๋˜์ง„ ์•Š๋Š”๋‹ค. 

    public ListResult<TestGetMembersResDto> testGetMembersV1() {

        List<TestGetMembersResDto> testGetMembersResDtoList = new ArrayList<>();

        List<Member> members = memberRepository.findAll();

        for(Member member : members) {
            TestGetMembersResDto testGetMembersResDto = TestGetMembersResDto.builder()
                    .memberId(member.getId())
                    .nickname(member.getNickname())
                    .imageUrl(member.getProfileImageUrl())
                    .postingCount((long)member.getPostings().size())
                    .build();
            testGetMembersResDtoList.add(testGetMembersResDto);
        }

        return responseService.getListResult(testGetMembersResDtoList);
    }

์ด๋ ‡๊ฒŒ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋œ๋‹ค๊ณ  ํ•ด๋„, ๋ฉค๋ฒ„ ๊ฐ์ฒด์—์„œ ํฌ์ŠคํŒ… ๊ฐœ์ˆ˜๋ฅผ ์ฐธ์กฐํ•ด์„œ ๊ฐ€์ ธ์˜ฌ ๋•Œ, ์—ฌ์ „ํžˆ ํฌ์ŠคํŒ… ํ…Œ์ด๋ธ”์„ ์กฐํšŒํ•˜๋Š” ์ฟผ๋ฆฌ๊ฐ€ ๋งค๋ฒˆ ๋‚˜๊ฐ„๋‹ค. ์—ฌ๊ธฐ์„œ ๊ฐ€์ ธ์˜จ getReference๋Š” ๊ฐ€์งœ๊ฐ์ฒด์ด๊ธฐ ๋•Œ๋ฌธ์— ์‹ค์ œ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ฟผ๋ฆฌ๋ฅผ ์กฐํšŒํ•  ์ˆ˜๋ฐ–์— ์—†๋Š” ๊ฒƒ์ด๋‹ค!

 

 

 

๋”ฐ๋ผ์„œ repository์—์„œ ๊ฐ’์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ fetch join์„ ์‚ฌ์šฉํ•˜์—ฌ ํฌ์ŠคํŒ…์˜ ์‹ค์ œ ์ •๋ณด๋„ ํ•œ ๋ฒˆ์— ๊ฐ€์ ธ์˜ค๋„๋ก ํ•œ๋‹ค.

 

    @Query("select m from Member m left join fetch m.postings")
    List<Member> findAllFetch();

 

์ด๋ ‡๊ฒŒ ํ•œ๋ฒˆ์— ๊ฐ’์„ ๊ฐ€์ ธ์™”์„ ๋•Œ๋Š” ์ฟผ๋ฆฌ๊ฐ€ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค!

 

 

 

์ด๊ฑธ JMeter๋ฅผ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธํ•ด๋ณด์ž!

 

๋ฐ์ดํ„ฐ๋ฅผ ๋ช‡ ๋ช…๋งŒ ๋„ฃ๊ฒŒ ๋œ๋‹ค๋ฉด ํ…Œ์ŠคํŠธ ์ฐจ์ด๊ฐ€ ์–ผ๋งˆ ๋‚˜์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด์„œ 5000๋ช… ์ •๋„์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๊ณ  ํ…Œ์ŠคํŠธํ•ด๋ณด์•˜๋‹ค.

์ด๋ ‡๊ฒŒ ํšŒ์› ์ •๋ณด๋ฅผ ์ž‘์„ฑํ•ด ๋†“์•˜๋‹ค.!

 

 

๐Ÿซง fetch join์„ ์‚ฌ์šฉํ•˜๊ธฐ ์ „๊ณผ ํ›„

 

์•ฝ 2.6๋ฐฐ ์ •๋„ ๊ฐœ์„ ๋œ ๊ฒƒ์„ ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ๋‹ค ใ…Žใ…Ž

ํฌ์ŠคํŠธ๋งจ์œผ๋กœ ํ™•์ธํ•˜๋ฉด ์•ฝ 3๋ฐฐ๊นŒ์ง€๋„ ์ฐจ์ด๊ฐ€ ๋‚ฌ์—ˆ๋‹ค. (709ms -> 237ms)