본문 바로가기
Spring

[Spring] Querydsl Group By 성능 개선

by 가드 2022. 11. 23.
728x90

기본적으로 Mysql에서 Group By를 실행하면 실행 계획 Extra 컬럼에 Using temporary 또는 Using filesort가 발생된다.

Using Temporary (임시 테이블)

Group By 할때 Mysql 엔진이 스토리지 엔진으로부터 받아온 레코드를 내부적으로 임시 테이블을 생성해서 사용한다. 메모리로 테이블을 생성했다가 테이블의 크기가 커지면 디스크로 옮겨지는 특성이 있기 때문에 디스크에 생성되면 이때 성능 이슈가 발생된다.

Using filesort (드라이빙 정렬)

요구하는 조건이 인덱스를 통해 정렬을 할 수 없다면 FileSort를 사용하게 된다. 임시 테이블의 정렬도 FileSort에 해당된다. 그러므로 FileSort는 레코드가 많아질수록 성능이 많이 떨어지게 된다.

Using filesort 제거 방법

정렬 옵션을 꺼주면 되기 때문에 매우 간단하다. order by null을 추가하면 된다.

그러나 Querydsl은 order by null을 지원하지 않는다. 그래서 우회하는 방식을 사용해야 한다.

 Querydsl order by null 우회 방식

// OrderSpecifier 상속 클래스 생성
public class OrderByNull extends OrderSpecifier {
    public static final OrderByNull DEFAULT = new OrderByNull();
    public OrderByNull() {
        super(Order.ASC, NullExpression.DEFAULT, NullHandling.Default);
    }
}

// OrderBy에 OrderByNull 클래스 적용
public List<Shop> orderByNull(Long shopNo) {
	return jpaQueryFactory.selectFrom(shop)
            .where(shop.shopNo.eq(shopNo))
            .groupBy(shop.shopNo)
            .orderBy(OrderByNull.DEFAULT)
            .fetch();
}

OrderSpecifier를 상속받은 OrderByNull 클래스를 생성하고 super 생성자에 기본 값들로 선언해주고 JpaQueryFactory의 orderBy 함수에 OrderByNull 클래스를 적용해주면 Null이 적용된다.

임시 테이블 생성은 Group By 컬럼을 인덱스를 생성해주면 되는데 조건에 따라 실행계획 달라지므로 쿼리에 맞는 인덱스를 생성해주도록 하자. 참고사항 : Index 최적화

 

300x250

댓글