Go(AWS SDK v2)에서의 DynamoDB Query
Query는 파티션 하나를 읽으며, 필요하면 정렬 키로 범위를 좁힙니다(Query vs Scan에서 그것이 옳은 선택인 시점을, 키 조건 표현식에서 사용 가능한 모든 연산자를 다룹니다). AWS SDK for Go v2가 보태는 것은 QueryPaginator입니다. LastEvaluatedKey 루프를 for 루프로 바꿔 주면서, 그 과정에서 여러분이 멈출 기회를 조용히 앗아갑니다.
코드
package main
import (
"context"
"fmt"
"log"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
func main() {
ctx := context.TODO()
cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion("us-east-1"))
if err != nil {
log.Fatalf("load config: %v", err)
}
client := dynamodb.NewFromConfig(cfg)
paginator := dynamodb.NewQueryPaginator(client, &dynamodb.QueryInput{
TableName: aws.String("Music"),
KeyConditionExpression: aws.String(
"#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)"),
ExpressionAttributeNames: map[string]string{
"#hashKey": "Artist",
"#rangeKey": "SongTitle",
},
ExpressionAttributeValues: map[string]types.AttributeValue{
":hashKeyValue": &types.AttributeValueMemberS{Value: "Arturo Sandoval"},
":rangeKeyValue": &types.AttributeValueMemberS{Value: "C"},
},
})
var items []map[string]types.AttributeValue
for paginator.HasMorePages() {
page, err := paginator.NextPage(ctx)
if err != nil {
log.Fatalf("query: %v", err)
}
items = append(items, page.Items...)
}
fmt.Printf("Found %d items\n", len(items))
}설명
Limit은 페이지네이터가 읽는 양을 제한하지 않습니다. 돈이 드는 것은 이쪽입니다. 위 입력에 Limit: aws.Int32(5)를 설정하고 약 60 KB짜리 항목 30개로 이루어진 파티션에서 실행하면 이렇게 나옵니다:
page 1: Count=5 CU=37.0 page 5: Count=5 CU=37.0
page 2: Count=5 CU=37.0 page 6: Count=5 CU=37.0
page 3: Count=5 CU=37.0 page 7: Count=0 CU=0.0
page 4: Count=5 CU=37.0 total: 30 items, 222.0 units서른 개가 모두 돌아왔습니다. Limit은 페이지 크기이고, 페이지네이터의 일은 페이지가 떨어질 때까지 계속 요청하는 것이므로 둘은 정확히 서로를 상쇄합니다. AWS는 그것을 "the maximum number of items to evaluate (not necessarily the number of matching items)"라고 정의합니다(2026-07-28 확인). 처음 다섯 개만 원한다면 첫 페이지 뒤에 여러분이 직접 루프를 break하세요.
작은 페이지는 덜이 아니라 조금 더 비쌉니다. 같은 파티션을 Limit 없이 읽으면 두 페이지에 220.0 단위이고, Limit: 5에서는 일곱 번의 호출에 222.0이 들었습니다. 각 페이지가 자기 바이트 합계를 다음 4 KB 경계로 올림하므로 페이지가 많아질수록 반올림도 늘고, 여기에 여섯 번의 추가 왕복 지연이 더해집니다. "덜 읽으려고" Limit을 낮추면 둘 다 얻지 못합니다.
루프는 언제나 데이터보다 한 번 더 호출합니다. 위의 7페이지는 항목을 0개 돌려주었습니다. DynamoDB는 Limit에 도달했다면 뒤에 무엇이 이어지든 상관없이 LastEvaluatedKey를 돌려주고, HasMorePages()는 그것을 믿습니다. 그래서 Limit을 건 페이지네이터는 낭비된 요청으로 끝나며, 페이지마다 붙은 부수 효과(진행 표시줄, 배치 플러시, 로그 한 줄)는 빈 페이지에 대고 한 번 더 발동합니다. len(page.Items)로 가드하세요.
HasMorePages()는 첫 요청 전에도 true입니다. for 루프가 진입이라도 하도록 true로 초기화되므로, 그것은 "데이터가 있다"는 검사가 아니라 루프 조건입니다. 쿼리를 할지 말지 정하려고 호출하면 언제나 그렇다고 답합니다.
오류는 페이지 단위로 드러나며, 부분 읽기는 실재하는 상태입니다. NextPage는 다른 호출과 똑같이 감싸인 smithy 오류를 돌려주므로, 문자열 비교 대신 *types.ProvisionedThroughputExceededException 같은 타입에 대해 errors.As로 풀어내세요. 예제의 log.Fatalf는 이미 모은 페이지를 내버립니다. 서비스라면 보통 items를 지키고 어디까지 갔는지 보고하고 싶을 것입니다.
파티션을 거꾸로 읽는 유일한 방법은 ScanIndexForward입니다. 정렬 키 내림차순이면 ScanIndexForward: aws.Bool(false)로 설정하세요. 그 밖의 "정렬 기준"은 없습니다. 순서는 정렬 키에서 나오고, 다른 순서가 필요하면 다른 인덱스가 필요합니다. IndexName: aws.String("...")은 쿼리 전체를 그 인덱스로 옮깁니다.
두 패키지가 이것을 짧게 만들어 줍니다. github.com/aws/aws-sdk-go-v2/feature/dynamodb/expression은 expression.Key("Artist").Equal(expression.Value("Arturo Sandoval"))에서 키 조건과 두 플레이스홀더 맵을 만들어 주며, 손으로 쓴 #hashKey/:hashKeyValue 쌍과 그에 딸린 예약어 위험까지 함께 없앱니다. attributevalue.UnmarshalListOfMaps(page.Items, &songs)는 한 페이지를 곧장 []Song으로 바꿉니다.
시각적으로 해보기
두 개의 플레이스홀더 맵이야말로 손으로 치기보다 생성할 값어치가 있는 부분입니다. 무료 DynamoDB Expression Builder가 키 조건을 짝이 맞는 ExpressionAttributeNames 및 ExpressionAttributeValues와 함께 조립해 Go 리터럴로 내보내므로, 이름과 값이 어긋날 수 없습니다.
여러분의 테이블에 쿼리를 실행하려면 — 키 조건 폼, 스크롤하면 페이지를 넘기는 그리드, 요청을 다시 Go로 복사 — DynoTable을 다운로드하세요.
관련 예제
- Java의 DynamoDB Query — AWS SDK for Java 2.x로 하는 같은 쿼리.
- Go의 DynamoDB Scan — 파티션으로 키를 잡을 수 없을 때.
- 페이지네이션 —
LastEvaluatedKey,ExclusiveStartKey, 그리고Limit이 페이지 크기가 아닌 이유. - "Query condition missed key schema element" — 키 조건이 엉뚱한 속성을 지목했거나 파티션 키를 빠뜨린 경우.
- "Query key condition not supported" — contains나 두 번째 정렬 키 조건처럼 키 조건이 쓸 수 없는 연산자.
참고 자료
- Query — Amazon DynamoDB API Reference
- Use Query with an AWS SDK or CLI — Amazon DynamoDB Developer Guide
- dynamodb package — AWS SDK for Go v2 (pkg.go.dev)
- expression package — AWS SDK for Go v2 (pkg.go.dev)
- Querying tables — Amazon DynamoDB Developer Guide
2026-07-28에 go1.26.5와 aws-sdk-go-v2/service/dynamodb v1.62.1로, 포트 9000의 DynamoDB Local(amazon/dynamodb-local)을 상대로, 약 60 KB짜리 항목 30개로 이루어진 파티션에서 측정했습니다. 페이지별 개수와 용량 수치는 그대로 옮긴 출력입니다. DynamoDB Local은 문서화된 반올림 규칙을 적용합니다. 절대 단위는 형태를 보여 주는 예시로 받아들이고, 용량을 산정하기 전에 실제 서비스에서 측정하세요.