createdAt 을 GSI로 설정하여 날짜별 조회를 하려했다. 데이터 생성 초기에는 빠른 시간 내에 데이터 조회가 가능했으나, 데이터가 쌓이면서 GSI를 통한 조회 시간은 7초 이상을 넘어가기 시작했다.
val allUserRoutine = userTaskRepository.findAllByGSIAndCreatedAt(
KeyBuilder.userTaskPK(storeId),
KeyBuilder.userTaskSK(null, null),
todayStart,
todayEnd
)
override fun findAllByGSIAndCreatedAt(pk: String, sk: String, startTime: String, endTime:String): List<T> {
val conditional: QueryConditional = QueryConditional.sortBeginsWith(
Key.builder()
.partitionValue(pk)
.sortValue(sk)
.build()
)
val queryRequest = QueryEnhancedRequest.builder()
.queryConditional(conditional)
.filterExpression(
Expression.builder()
.expression("created_at BETWEEN :start AND :end")
.expressionValues(
mapOf(
":start" to AttributeValue.builder().s(startTime).build(),
":end" to AttributeValue.builder().s(endTime).build()
)
)
.build()
)
.build()
return dynamoDbTable.query(queryRequest).items().toList()
}
GSI와 createdAt 을 이용해 조회하는 구현체에 문제가 있어 느려진건가하는 생각이 들었다. 하지만 조회 과정에서는 문제가 없었고, 적합한 인덱스 방식을 사용했는지에 대한 문제였다.
dynamodb의 데이터 조회 방식에는 query 방식과 scan 방식이 있는데 scan보다 query 가 훨씬 효율적이며 PK를 기반으로 데이터를 조회하므로 적합한 인덱스를 설정했다면 빠르게 작동한다.
따라서 적합한 pk 를 설정했는지 고민하는게 첫번쨰 순서였다.
기존 DB 설계시에는 날짜별 조회라는 조건이 없어 데이터의 고유 id값을 조합해 pk,sk 를 구성했다. 하지만 이후에 날짜별로 조회하는 기능의 필요성을 깨닫고 GSI로 createdAt을 설정해 between을 이용해 날짜별 조회를 구현했다.
초기 DB설계에 있어서 확장성을 고려하지 못하고 pk,sk를 설정했던 실수였다.
이번 버전 업데이트부터는 날짜별 조회가 필수적이고 그 조회시간이 빨라야하기에 pk,sk 패턴을 바꿔야겠다 생각이 들었다.
기존에는
pk : STORE#{storeId}
sk : ROUTINE#{routineId}#USERTASK#{userTaskId}
이렇게 pk,sk 를 설정해 routineId별 세부 사항을 조회하는 등의 조회 조건을 가졌다. 하지만 이에 createdAt 을 추가했다.
pk : STORE#{storeId}
sk : CREATEDAT#{createdAt}#ROUTINE#{routineId}#USERTASK#{userTaskId}