티스토리 뷰

사용자의 구독 이력UserSubscribeHistory 을 확인하는 find 함수

기존 JPA Query

다음 코드는 사용자가 해당 채널을 구독하는지 조회하는 JPA Query이다.

  • 사용자의 구독 이력 UserSubscribeHistory 에서
  • 구독하는 채널명 channelName 인지 확인하고
  • UserSubscribeStatus 구독 상태 여부에 따라 UserSubscribeHistory를 반환한다.
fun find(channelName: String, status: UserSubscribeStatus? = null): UserSubscribeHistory? {
    return queryFactory.select(userSubscribeHistory)
        .from(userSubscribeHistory)
        .where(
            userSubscribeHistory.channelName.eq(channelName),
            status?.let { userSubscribeHistory.status.eq(status) }
        )
        .limit(1)
        .fetchOne()
}

 

ChatGPT가 변경해준 JPA Query

fun findModifiedByGPT(channelName: String, status: UserSubscribeStatus? = null): UserSubscribeHistory? =
    queryFactory.selectFrom(userSubscribeHistory)
        .where(
            userSubscribeHistory.channelName.eq(channelName),
            status?.let { userSubscribeHistory.status.eq(it) }
        )
        .orderBy(userSubscribeHistory.id.desc())
        .fetchFirst()

 

 

변경된 사항

selectFrom

select + from 절 -> selectFrom

 

 

단일 표현식 함수 (Single-expression functions)

fun 함수명():반환타입 {
	return
}

fun 함수명():반환타입 = 결과

Kotlin은 함수가 하나의 표현식(Expression)만으로 구성되어 있다면,

return 결과를 중괄호 {} 대신 = 을 사용하여 함수 결과를 직접 반환할 수 있다.

이 경우, 함수의 마지막 표현식이 자동으로 반환된다.

 

 

limit -> orderBy 와 fetchFirst 로 대체

        .orderBy(userSubscribeHistory.id.desc())
        .fetchFirst()
  • orderBy(userSubscribeHistory.id.desc()) : id 열을 기준으로 내림차순으로 결과를 정렬
  • fetchFirst() : 첫 번째 결과를 반환

userSubscribeHistory.id가 고유한 식별자이고, 가장 최근 항목(즉, 가장 높은 ID를 가진 항목)이 반환되어야 한다고 가정한 결과이다.

다른 기준을 사용한다면 orderBy 로 정렬 기준을 수정한다.

 

 

limit(1) 보다 orderBy + fetchFirst 를 사용하는게 효율적인 이유

1. limit(1)은 대량의 데이터가 있는 경우 쿼리 실행 속도를 늦출 수 있다.

MySQL의 limit 은 항상 쿼리의 마지막에 실행된다.

데이터 전체를 조회해서 메모리에 저장한 후에, limit 으로 실제 사용할 데이터만 추출하고

나머지 데이터는 버리는 방식으로 동작하기 때문에 대용량 데이터를 처리할 경우 실행 속도가 느릴 수 있다.

 

limit 절은 쿼리 결과에서 지정된 순서에 위치한 레코드만 가져오고자 할 때 사용한다.

select * from employees
where emp_no between 10001 and 10010
order by first_name
limit 0, 5;

위의 쿼리는 다음과 같은 순서로 실행된다.

  1. employees 에서 where 절의 검색 조건에 일치하는 레코드를 전부 읽어 온다.
  2. 1번에서 읽어온 레코드를 first_name 칼럼값에 따라 정렬한다.
    • 상위 5건이 정렬이 완료되면 즉시 쿼리를 멈춘다.
  3. 정렬된 결과의 상위 5건만 사용자에게 반환한다.

 

2.  orderBy, fetchFirst는 인덱스를 사용하여 정렬한다.

 

3. orderBy, fetchFirst는 다양한 데이터베이스에서 지원되기 때문에 데이터베이스 간 이식성을 향상시킬 수 있다.

 

 

 

결과 테스트

간결하고 함수형으로 변환되기는 했는데, 뭐가 더 실무에서 많이 쓰고 좋은(?) 코드인지는 아직 아리송하다..

그런데 일단 쿼리문이 더 효율성 있는 걸로 바뀌었으니까, 두개 성능 차이가 있을 거 같아 테스트 코드를 돌려보았다.

이렇게나 성능이 차이난다고..?

 

나가는 하이버네이트 쿼리문은 이렇게 바뀌었다.

Hibernate: 
    select
        userloanhi0_.id as id1_2_,
        userloanhi0_.book_name as book_nam2_2_,
        userloanhi0_.status as status3_2_,
        userloanhi0_.user_id as user_id4_2_ 
    from
        user_loan_history userloanhi0_ 
    where
        userloanhi0_.book_name=? 
        and userloanhi0_.status=? limit ?
Hibernate: 
    select
        userloanhi0_.id as id1_2_,
        userloanhi0_.book_name as book_nam2_2_,
        userloanhi0_.status as status3_2_,
        userloanhi0_.user_id as user_id4_2_ 
    from
        user_loan_history userloanhi0_ 
    where
        userloanhi0_.book_name=? 
        and userloanhi0_.status=? 
    order by
        userloanhi0_.id desc limit ?

아니 뭐야 둘다 limit 는 있잖아..?

뭐지 분명 성능이 좋아지긴 했는데 둘다 limit 가 있어서 더 헷갈려.. 인덱스를 타게 되는건가?

이 부분은 좀 더 찾아봐야겠다.

 

 

 

 

 

 

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함