페이지네이션 with 빅쿼리

신연우·2024년 11월 10일

WIL

목록 보기
15/21

배경

빅쿼리 테이블에서 가지고 있는 정보를 가져와서 사용하고 싶은 요구사항이 들어왔습니다. 그러나 대용량 데이터를 가져올 때 속도가 꽤 걸리는 문제가 있었습니다.

빅쿼리 임시 테이블

임시 테이블에서는 스토리지 비용이 발생하지 않지만, 쿼리 결과를 영구 테이블에 쓰면 데이터 저장 요금이 청구됩니다. 대화형 및 일괄 쿼리가 모두 포함된 모든 쿼리 결과가 일부 예외를 제외하고 약 24시간 동안 임시 테이블에 캐시 처리됩니다.
공식 문서

방법을 찾기 위해 구글링을 하던 도중 공식 문서에서 임시 테이블이라는 개념을 접하게 되었습니다.

빅쿼리에서는 쿼리 결과를 임시 테이블에 저장해두고, 이 결과를 캐싱해두기 때문에 임시 테이블을 조회할 때 상당히 빠른 속도로 조회할 수 있습니다.

현재는 애플리케이션에서 페이지네이션 쿼리를 매번 실행하고 있었는데, 차라리 데이터를 한 번에 쿼리해서 임시 테이블에 데이터를 캐시 처리한다면, 이 정보를 더 빠르게 가져올 수 있지 않을까 싶었습니다.

빅쿼리 Job

하지만, 임시 테이블에 데이터를 한 번에 넣는다는 건 결국 애플리케이션에 한 번에 데이터를 들고 온다는 뜻이라 기존에 메모리 등의 자원을 고려한 페이지네이션 처리 로직의 존재 이유가 사라지게 됩니다.

그래서 임시 테이블에 필요한 데이터를 한 번에 캐시 처리하되, 애플리케이션에는 들고 오지 않는 방법이 없을까해서 찾아보다 빅쿼리 Job 개념을 알게 되었습니다.

빅쿼리 Job 예시

빅쿼리에서 쿼리를 하게 되면 내부적으로 Job이 실행됩니다. 이 Job에는 고유한 ID가 있고, 해당 Job을 다시 실행하면 동일한 쿼리 결과를 얻을 수 있습니다.

kotlin에서 사용해보기

class BigQueryExampleRepositoryImpl(
    private val bigQuery: BigQuery,
) {
    fun createJob(queryConfig: QueryJobConfiguration): Job {
        val jobId = createJobId()
        val job = bigQuery.createJob(JobInfo.of(jobId, queryConfig))
        
        if (job.status.error != null) {
            throw RuntimeException("Failed to execute BigQuery job: ${job.status.error}")
        }
        
        return job
    }

    fun createJobId(): JobId {
        return JobId.newBuilder()
            .setLocation("us")
            .setJob(UUID.randomString())
            .build()
    }
}

이렇게 kotlin에서 빅쿼리의 Job을 생성할 수 있습니다. 이제 Job의 결과를 가져올 때 페이지네이션만 적용해서 쿼리를 가져오면 됩니다.

fun getQueryResult() {
    val job = createJob(/* 생략 */)
    val options = listOfNotNull(
        BigQuery.QueryResultsOption.pageSize(size),
        cursor?.let { BigQuery.QueryResultsOption.pageToken(it) }
    )
    
    return job.getQueryResults(*options)
}

BigQuery.QueryResultsOption을 통해 Job의 임시 테이블에서 쿼리 결과를 가져올 때 페이지네이션을 할 수 있습니다.

결론

  • 임시 테이블에서 결과를 가져오게 바뀌면서 캐시를 타기 때문에 처음 Job을 만들 때를 제외하고는 조회 속도가 매우 빨라집니다. (쿼리를 페이지네이션마다 새롭게 실행하지 않기 때문)
  • getQueryResult 반복을 비동기로 처리한다면 중간에 서버가 shutdown 될 때 graceful shutodwn을 적용받을 수 있습니다.
  • 위 사유로 중간에 중단되었을 때 jobId, cursor 값만 알 수 있다면 재시도 할 수 있습니다.
profile
남들과 함께하기 위해서는 혼자 나아갈 수 있는 힘이 있어야 한다.

0개의 댓글