기존 방법은 @OneToMany의 기본 설정인 FetchType.LAZY 으로, 다른 설정 없이 get method를 통해 필요할 때 가져오는 방식이다.

그 중, Gallery 엔티티는 사진에 대한 정보를 가지고 있는 Image 엔티티와 @OneToOne 관계이다.

클라이언트에게 응답을 내려줄 때, Gallery를 응답을 위한 DTO로 변환하는 과정에서 무수히 많은 쿼리가 발생한다.

아래는 현재 조회 했을 때 발생하는 쿼리이다.

Hibernate: select i1_0.product_id,i1_1.created_at,i1_1.product_info_id,i1_1.tsid,i1_1.updated_at,i1_1.user_id,i1_0.bride_father_is_deceased,i1_0.bride_father_name,i1_0.bride_mother_is_deceased,i1_0.bride_mother_name,i1_0.bride_name,i1_0.bride_relation,i1_0.contents,i1_0.cover_contents,i1_0.groom_father_is_deceased,i1_0.groom_father_name,i1_0.groom_mother_is_deceased,i1_0.groom_mother_name,i1_0.groom_name,i1_0.groom_relation,i1_0.guestbook_check,i1_0.image_id,i1_0.share_thumbnail_id,i1_0.title,i1_0.date,i1_0.date_type,i1_0.detail,i1_0.geography,i1_0.place_address,i1_0.place_name from invitation i1_0 join product i1_1 on i1_0.product_id=i1_1.product_id where i1_1.tsid=?
Hibernate: select o1_0.orders_id,o1_0.created_at,o1_0.is_paid,o1_0.product_id,o1_0.updated_at,o1_0.user_id from orders o1_0 left join product p1_0 on p1_0.product_id=o1_0.product_id where p1_0.product_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select p1_0.product_id,p1_0.priority_id,p1_0.name,p1_0.priority from priority p1_0 where p1_0.product_id=? order by p1_0.priority
Hibernate: select c1_0.product_id,c1_0.id,c1_0.name,c1_0.phone_number,c1_0.relation,c1_0.wedding_side from contact c1_0 where c1_0.product_id=?
Hibernate: select t1_0.product_id,t1_0.transport_id,t1_0.detail,t1_0.kind from transport t1_0 where t1_0.product_id=?
Hibernate: select g1_0.product_id,g1_0.gallery_id,g1_0.image_id,g1_0.priority from gallery g1_0 where g1_0.product_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?
Hibernate: select a1_0.product_id,a1_0.id,a1_0.account_number,a1_0.bank_name,a1_0.name,a1_0.wedding_side from account a1_0 where a1_0.product_id=?
Hibernate: select st1_0.id,st1_0.contents,st1_0.image_id,st1_0.title from share_thumbnail st1_0 where st1_0.id=?
Hibernate: select i1_0.image_id,i1_0.origin_name,i1_0.store_file_name,i1_0.url from image i1_0 where i1_0.image_id=?

개선 방법

QueryDsl을 사용하여 fetch join을 통해 Invitation을 조회하기로 했다.

Invitation 엔티티는 6개의 OneToMany 관계를 가지고 있고, 4개의 ManyToOne 관계를 가지고 있다.

XToMany 관계에서는 두 개 이상의 컬렉션을 fetch join을 할 수 없다. 그렇기 때문에 모든 연관 관계들을 fetch join 할 때 가장 많은 컬렉션을 가질 엔티티 하나에만 Invitation을 가져올 때 fetch join을 수행했다.

    @Override
    public Invitation findByIdWithALL(Long productId) {

        return queryFactory
                .selectFrom(invitation)
                .join(invitation.shareThumbnail, shareThumbnail).fetchJoin()
                .join(invitation.shareThumbnail.image, new QImage("shareThumbnailImage")).fetchJoin()
                .join(invitation.mainImage, new QImage("mainImage")).fetchJoin()
                .join(invitation.productInfo, productInfo).fetchJoin()
                .join(invitation.gallery, gallery).fetchJoin()
                .join(gallery.image, image).fetchJoin()
                .where(invitation.id.eq(productId))
                .fetchFirst();
    }

invitation 조회 시, OneToOne 관계인 엔티티들은 Fetch Join을 하고 Gallery의 Image 엔티티와 Gallery를 fetch join을 했다.

이렇게 되면 Gallery와 Gallery내의 Image들이 한꺼번에 조회되어 최적화할 수 있다.

나머지 LazyLoading되는 XToMany 관계를 가진 엔티티들은 Hibernate의 default_batch_fetch_size: 20 설정을 통해 in 절로 가져왔다.