[QueryDSL] Cross Join 이 발생한다면,

Walter Mitty·2023년 4월 8일
0

JPA

목록 보기
1/2

JPA 환경에서 QueryDSL을 사용하다보면 Join 쿼리 작성시 무심코 발생하는 Cross Join을 놓칠 때가 많다.

Cross Join 이란 묵시적 조인으로 조인을 명시하지 않고 엔터티에서 다른 엔터티를 조회해서 비교하는 경우 JPA가 알아서 해주는 조인이다.


Cross Join의 단점 : Cross Join을 하게 되면 나올 수 있는 데이터가 그냥 조인들보다 많아지기 때문에 성능상의 단점이있다.
따라서, 크로스 조인을 피하기 위해서 쿼리를 보고 명시적 조인을 이용해서 해결하는 것이 좋다.

Cross Join 발생 코드

public List<ProductReadOneDto> findProdInfo(Long prodNum) {
		List<ProductReadOneDto> result = jpaQueryFactory
				.selectFrom(p)
				.leftJoin(q).on(p.prodNum.eq(q.prodNum.prodNum))
				.leftJoin(r).on(p.prodNum.eq(r.orderDetail.id.prodNum))
				.leftJoin(br).on(r.reviewNum.eq(br.reviewNum))
				.where(p.prodNum.eq(prodNum))
				.distinct()
				.transform(groupBy(p.prodNum).list(Projections.constructor(ProductReadOneDto.class,
						p.prodNum, p.seller.companyName, p.seller.sellerId.id, p.category, p.name,
						p.originPrice, p.percentage, p.week, p.detail, p.productImgUrl, p.status,
						list(Projections.constructor(QnaReadOneResponseDto.class,
								q.qnaNum, q.userId.id, q.queTitle, q.queContent,q.queCreatedDate,
								q.ansContent, q.ansCreatedDate, q.qnaImgUrl).as("qnas")), 
						list(Projections.constructor(ReviewReadListResponseDto.class,
								r.user.id, r.reviewNum, r.title, r.content, r.sort, r.createdDate, r.stars).as("reviews")), 
						list(Projections.constructor(BestReviewReadResponseDto.class,
								br.reviewNum, br.createdDate)))));
		return result;
	}
select
        distinct product0_.num as col_0_0_,
        product0_.num as col_1_0_,
        seller4_.company_name as col_2_0_,
        seller4_.seller_id as col_3_0_,
        product0_.category as col_4_0_,
        product0_.name as col_5_0_,
        product0_.origin_price as col_6_0_,
        product0_.percentage as col_7_0_,
        product0_.week as col_8_0_,
        product0_.detail as col_9_0_,
        product0_.product_img_url as col_10_0_,
        product0_.status as col_11_0_,
        qna1_.num as col_12_0_,
        qna1_.user_id as col_13_0_,
        qna1_.que_title as col_14_0_,
        qna1_.que_content as col_15_0_,
        qna1_.que_created_date as col_16_0_,
        qna1_.ans_content as col_17_0_,
        qna1_.ans_created_date as col_18_0_,
        qna1_.qna_img_url as col_19_0_,
        review2_.user_id as col_20_0_,
        review2_.num as col_21_0_,
        review2_.title as col_22_0_,
        review2_.content as col_23_0_,
        review2_.sort as col_24_0_,
        review2_.created_date as col_25_0_,
        review2_.stars as col_26_0_,
        bestreview3_.review_num as col_27_0_,
        bestreview3_.created_date as col_28_0_ 
    from
        product product0_ 
    left outer join
        qna qna1_ 
            on (
                product0_.num=qna1_.prod_num
            ) 
    left outer join
        review review2_ 
            on (
                product0_.num=review2_.prod_num
            ) 
    left outer join
        best_review bestreview3_ 
            on (
                review2_.num=bestreview3_.review_num
            ) cross //크로스 조인 발생 !!!!
    join
        seller_info seller4_ 
    where
        product0_.seller_id=seller4_.seller_id 
        and product0_.num=?

👇

Cross Join을 명시적 조인(Inner Join)으로 변경

public List<ProductReadOneDto> findProdInfo(Long prodNum) {
		List<ProductReadOneDto> result = jpaQueryFactory
				.selectFrom(p)
				.join(p.seller, s) //명시적 조인(inner join)을 추가해줬다.
				.leftJoin(q).on(p.prodNum.eq(q.prodNum.prodNum))
				.leftJoin(r).on(p.prodNum.eq(r.orderDetail.id.prodNum))
				.leftJoin(br).on(r.reviewNum.eq(br.reviewNum))
				.where(p.prodNum.eq(prodNum))
				.distinct()
				.transform(groupBy(p.prodNum).list(Projections.constructor(ProductReadOneDto.class,
						p.prodNum, p.seller.companyName, p.seller.sellerId.id, p.category, p.name,
						p.originPrice, p.percentage, p.week, p.detail, p.productImgUrl, p.status,
						list(Projections.constructor(QnaReadOneResponseDto.class,
								q.qnaNum, q.userId.id, q.queTitle, q.queContent,q.queCreatedDate,
								q.ansContent, q.ansCreatedDate, q.qnaImgUrl).as("qnas")), 
						list(Projections.constructor(ReviewReadListResponseDto.class,
								r.user.id, r.reviewNum, r.title, r.content, r.sort, r.createdDate, r.stars).as("reviews")), 
						list(Projections.constructor(BestReviewReadResponseDto.class,
								br.reviewNum, br.createdDate)))));
		return result;
select
        distinct product0_.num as col_0_0_,
        product0_.num as col_1_0_,
        seller1_.company_name as col_2_0_,
        seller1_.seller_id as col_3_0_,
        product0_.category as col_4_0_,
        product0_.name as col_5_0_,
        product0_.origin_price as col_6_0_,
        product0_.percentage as col_7_0_,
        product0_.week as col_8_0_,
        product0_.detail as col_9_0_,
        product0_.product_img_url as col_10_0_,
        product0_.status as col_11_0_,
        qna2_.num as col_12_0_,
        qna2_.user_id as col_13_0_,
        qna2_.que_title as col_14_0_,
        qna2_.que_content as col_15_0_,
        qna2_.que_created_date as col_16_0_,
        qna2_.ans_content as col_17_0_,
        qna2_.ans_created_date as col_18_0_,
        qna2_.qna_img_url as col_19_0_,
        review3_.user_id as col_20_0_,
        review3_.num as col_21_0_,
        review3_.title as col_22_0_,
        review3_.content as col_23_0_,
        review3_.sort as col_24_0_,
        review3_.created_date as col_25_0_,
        review3_.stars as col_26_0_,
        bestreview4_.review_num as col_27_0_,
        bestreview4_.created_date as col_28_0_ 
    from
        product product0_ 
    inner join
        seller_info seller1_ 
            on product0_.seller_id=seller1_.seller_id 
    left outer join
        qna qna2_ 
            on (
                product0_.num=qna2_.prod_num
            ) 
    left outer join
        review review3_ 
            on (
                product0_.num=review3_.prod_num
            ) 
    left outer join
        best_review bestreview4_ 
            on (
                review3_.num=bestreview4_.review_num
            ) 
    where
        product0_.num=?

그럼 아래처럼 명시적 inner join을 통해 seller 가 join되는 것을 볼 수 있다.

참고자료1
참고자료2

0개의 댓글