JPA 엔티티 조회 중 N + 1 문제는 정말 많이 일어난다.
아래는 Study Entity를 조회했을때 발생되는 쿼리의 양이다.
2022-06-13 15:53:30.059 DEBUG 29154 --- [nio-8080-exec-5] org.hibernate.SQL :
select
study0_.id as id1_4_,
study0_.closed as closed2_4_,
study0_.closed_date_time as closed_d3_4_,
study0_.full_description as full_des4_4_,
study0_.image as image5_4_,
study0_.path as path6_4_,
study0_.published as publishe7_4_,
study0_.published_date_time as publishe8_4_,
study0_.recruiting as recruiti9_4_,
study0_.recruiting_updated_date_time as recruit10_4_,
study0_.short_description as short_d11_4_,
study0_.title as title12_4_,
study0_.use_banner as use_ban13_4_
from
study study0_
where
study0_.path=?
2022-06-13 15:53:30.060 TRACE 29154 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [my-study]
2022-06-13 15:53:30.083 DEBUG 29154 --- [nio-8080-exec-5] org.hibernate.SQL :
select
members0_.study_id as study_id1_6_0_,
members0_.members_account_id as members_2_6_0_,
account1_.account_id as account_1_0_1_,
account1_.joined_at as joined_a2_0_1_,
account1_.modified_date as modified3_0_1_,
account1_.email as email4_0_1_,
account1_.email_token as email_to5_0_1_,
account1_.email_token_generated_at as email_to6_0_1_,
account1_.is_valid as is_valid7_0_1_,
account1_.nickname as nickname8_0_1_,
account1_.study_created_by_email as study_cr9_0_1_,
account1_.study_created_by_web as study_c10_0_1_,
account1_.study_registration_result_by_email_by_email as study_r11_0_1_,
account1_.study_registration_result_by_email_by_web as study_r12_0_1_,
account1_.study_updated_by_email as study_u13_0_1_,
account1_.study_updated_by_web as study_u14_0_1_,
account1_.password as passwor15_0_1_,
account1_.phone as phone16_0_1_,
account1_.bio as bio17_0_1_,
account1_.company as company18_0_1_,
account1_.image as image19_0_1_,
account1_.job as job20_0_1_,
account1_.location as locatio21_0_1_,
account1_.url as url22_0_1_
from
study_members members0_
inner join
account account1_
on members0_.members_account_id=account1_.account_id
where
members0_.study_id=?
2022-06-13 15:53:30.083 TRACE 29154 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [89]
2022-06-13 15:53:30.085 DEBUG 29154 --- [nio-8080-exec-5] org.hibernate.SQL :
select
tags0_.study_id as study_id1_7_0_,
tags0_.tags_id as tags_id2_7_0_,
tag1_.id as id1_9_1_,
tag1_.title as title2_9_1_
from
study_tags tags0_
inner join
tag tag1_
on tags0_.tags_id=tag1_.id
where
tags0_.study_id=?
2022-06-13 15:53:30.085 TRACE 29154 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [89]
2022-06-13 15:53:30.085 DEBUG 29154 --- [nio-8080-exec-5] org.hibernate.SQL :
select
zones0_.study_id as study_id1_8_0_,
zones0_.zones_id as zones_id2_8_0_,
zone1_.id as id1_10_1_,
zone1_.city as city2_10_1_,
zone1_.local_name_of_city as local_na3_10_1_,
zone1_.province as province4_10_1_
from
study_zones zones0_
inner join
zone zone1_
on zones0_.zones_id=zone1_.id
where
zones0_.study_id=?
2022-06-13 15:53:30.086 TRACE 29154 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [89]
2022-06-13 15:53:30.088 DEBUG 29154 --- [nio-8080-exec-5] org.hibernate.SQL :
select
managers0_.study_id as study_id1_5_0_,
managers0_.managers_account_id as managers2_5_0_,
account1_.account_id as account_1_0_1_,
account1_.joined_at as joined_a2_0_1_,
account1_.modified_date as modified3_0_1_,
account1_.email as email4_0_1_,
account1_.email_token as email_to5_0_1_,
account1_.email_token_generated_at as email_to6_0_1_,
account1_.is_valid as is_valid7_0_1_,
account1_.nickname as nickname8_0_1_,
account1_.study_created_by_email as study_cr9_0_1_,
account1_.study_created_by_web as study_c10_0_1_,
account1_.study_registration_result_by_email_by_email as study_r11_0_1_,
account1_.study_registration_result_by_email_by_web as study_r12_0_1_,
account1_.study_updated_by_email as study_u13_0_1_,
account1_.study_updated_by_web as study_u14_0_1_,
account1_.password as passwor15_0_1_,
account1_.phone as phone16_0_1_,
account1_.bio as bio17_0_1_,
account1_.company as company18_0_1_,
account1_.image as image19_0_1_,
account1_.job as job20_0_1_,
account1_.location as locatio21_0_1_,
account1_.url as url22_0_1_
from
study_managers managers0_
inner join
account account1_
on managers0_.managers_account_id=account1_.account_id
where
managers0_.study_id=?
2022-06-13 15:53:30.088 TRACE 29154 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [BIGINT] - [89]
나는 Study entity 하나만 조회했을 뿐인데
5번의 쿼리가 나갔다.
JPA 가 연관된 테이블들을 한번에 조회하지 않고
지연로딩으로 되어 있는 필드들을 조회할때마다 join하여 조회하기 때문에 발생하는 현상이다.
이러한 현상을 해결하기 위한 방법은 여러가지가 있지만
이번에 알아볼 방법은 @EntityGraph 어노테이션을 활용한 방법에 대해 포스팅 하겠다.
name : 엔티티 그래프 이름 정의
attributeNodes : 함께 조회할 속성 선택
@NamedEntityGraph(name = "Study.withAll",
attributeNodes = {
@NamedAttributeNode("tags"),
@NamedAttributeNode("zones"),
@NamedAttributeNode("managers"),
@NamedAttributeNode("members"),
})
Study.withAll이라는 이름을 가지고 tags, zones, managers, members 네 가지 attribute에 대해 Lazy 로딩을 사용하지 않겠다는 뜻.
@EntityGraph(value = "Study.withAll", type = EntityGraph.EntityGraphType.LOAD)
Study findByPath(String path);
value : 사용할 EntityGraph의 이름
type : EntityGraphType.Fetch && Load
2022-06-13 16:16:25.728 DEBUG 30751 --- [nio-8080-exec-5] org.hibernate.SQL :
select
study0_.id as id1_4_0_,
account2_.account_id as account_1_0_1_,
tag4_.id as id1_9_2_,
zone6_.id as id1_10_3_,
account8_.account_id as account_1_0_4_,
study0_.closed as closed2_4_0_,
study0_.closed_date_time as closed_d3_4_0_,
study0_.full_description as full_des4_4_0_,
study0_.image as image5_4_0_,
study0_.path as path6_4_0_,
study0_.published as publishe7_4_0_,
study0_.published_date_time as publishe8_4_0_,
study0_.recruiting as recruiti9_4_0_,
study0_.recruiting_updated_date_time as recruit10_4_0_,
study0_.short_description as short_d11_4_0_,
study0_.title as title12_4_0_,
study0_.use_banner as use_ban13_4_0_,
account2_.joined_at as joined_a2_0_1_,
account2_.modified_date as modified3_0_1_,
account2_.email as email4_0_1_,
account2_.email_token as email_to5_0_1_,
account2_.email_token_generated_at as email_to6_0_1_,
account2_.is_valid as is_valid7_0_1_,
account2_.nickname as nickname8_0_1_,
account2_.study_created_by_email as study_cr9_0_1_,
account2_.study_created_by_web as study_c10_0_1_,
account2_.study_registration_result_by_email_by_email as study_r11_0_1_,
account2_.study_registration_result_by_email_by_web as study_r12_0_1_,
account2_.study_updated_by_email as study_u13_0_1_,
account2_.study_updated_by_web as study_u14_0_1_,
account2_.password as passwor15_0_1_,
account2_.phone as phone16_0_1_,
account2_.bio as bio17_0_1_,
account2_.company as company18_0_1_,
account2_.image as image19_0_1_,
account2_.job as job20_0_1_,
account2_.location as locatio21_0_1_,
account2_.url as url22_0_1_,
members1_.study_id as study_id1_6_0__,
members1_.members_account_id as members_2_6_0__,
tag4_.title as title2_9_2_,
tags3_.study_id as study_id1_7_1__,
tags3_.tags_id as tags_id2_7_1__,
zone6_.city as city2_10_3_,
zone6_.local_name_of_city as local_na3_10_3_,
zone6_.province as province4_10_3_,
zones5_.study_id as study_id1_8_2__,
zones5_.zones_id as zones_id2_8_2__,
account8_.joined_at as joined_a2_0_4_,
account8_.modified_date as modified3_0_4_,
account8_.email as email4_0_4_,
account8_.email_token as email_to5_0_4_,
account8_.email_token_generated_at as email_to6_0_4_,
account8_.is_valid as is_valid7_0_4_,
account8_.nickname as nickname8_0_4_,
account8_.study_created_by_email as study_cr9_0_4_,
account8_.study_created_by_web as study_c10_0_4_,
account8_.study_registration_result_by_email_by_email as study_r11_0_4_,
account8_.study_registration_result_by_email_by_web as study_r12_0_4_,
account8_.study_updated_by_email as study_u13_0_4_,
account8_.study_updated_by_web as study_u14_0_4_,
account8_.password as passwor15_0_4_,
account8_.phone as phone16_0_4_,
account8_.bio as bio17_0_4_,
account8_.company as company18_0_4_,
account8_.image as image19_0_4_,
account8_.job as job20_0_4_,
account8_.location as locatio21_0_4_,
account8_.url as url22_0_4_,
managers7_.study_id as study_id1_5_3__,
managers7_.managers_account_id as managers2_5_3__
from
study study0_
left outer join
study_members members1_
on study0_.id=members1_.study_id
left outer join
account account2_
on members1_.members_account_id=account2_.account_id
left outer join
study_tags tags3_
on study0_.id=tags3_.study_id
left outer join
tag tag4_
on tags3_.tags_id=tag4_.id
left outer join
study_zones zones5_
on study0_.id=zones5_.study_id
left outer join
zone zone6_
on zones5_.zones_id=zone6_.id
left outer join
study_managers managers7_
on study0_.id=managers7_.study_id
left outer join
account account8_
on managers7_.managers_account_id=account8_.account_id
where
study0_.path=?
2022-06-13 16:16:25.729 TRACE 30751 --- [nio-8080-exec-5] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [my-study]