AWS - DynamoDB Pagination과 Where절
DynamoDB Pagination 기본 개념
DynamoDB는 Scan 또는 Query 작업을 수행할 때 모든 데이터를 한 번에 반환하지 않고,
페이지 단위로 나누어 데이터를 반환합니다.
주요 개념
- Limit : 한 번의 요청에서 반환할 최대 항목 수
- LastEvaluatedKey 현재 페이지의 마지막 항목 (다음 페이지 조회 시 사용)
- ExclusiveStartKey 다음 페이지의 조회 시작점 (이전 LastEvaluatedKey 값)
전체 데이터 조회 예제
따라서 일반적인 RDBMS의 "Select * From Users"와 같은 query로는 모든 데이터를 조회할 수 가 없습니다.
아래는 DynamoDB에서 1만개의 데이터를 페이지네이션으로 전체 데이터를 조회하는 예제입니다.
import boto3
# DynamoDB 클라이언트 생성
dynamodb = boto3.client("dynamodb", region_name="ap-northeast-2")
# 조회할 테이블명 설정
table_name = "Users"
# 페이지네이션을 위한 변수
limit = 1000 # 한 번에 가져올 항목 수
last_evaluated_key = None # 처음에는 LastEvaluatedKey 없음
total_items = [] # 전체 데이터를 저장할 리스트
page_count = 0 # 페이지 카운터
while True:
# Scan 요청 생성
scan_params = {
"TableName": table_name,
"Limit": limit,
}
# 이전 페이지의 마지막 키가 있으면 추가
if last_evaluated_key:
scan_params["ExclusiveStartKey"] = last_evaluated_key # 다음 페이지 시작점 지정
# DynamoDB Scan 실행
response = dynamodb.scan(**scan_params)
# 현재 페이지의 데이터 추가
items = response.get("Items", [])
total_items.extend(items) # 전체 데이터 리스트에 추가
page_count += 1
print(f"📌 페이지 {page_count}: {len(items)}개 데이터 로드 완료")
# LastEvaluatedKey가 있는 경우 계속 조회 (페이지네이션)
last_evaluated_key = response.get("LastEvaluatedKey")
# LastEvaluatedKey가 없으면 모든 데이터를 다 가져온 것이므로 종료
if not last_evaluated_key:
break
# 결과 출력
print(f"전체 데이터 개수: {len(total_items)}개")
DynamoDB는 Query 또는 Scan을 실행할 때 최대 1MB까지만 데이터를 반환합니다.
위의 예제는 limit = 1,000으로 지정하였지만,
설정이 없을 때는 1MB 이상 데이터가 있다면 LastEvaluatedKey를 반환합니다..
DynamoDB에서 Where절
SQL에서는 WHERE 조건만으로 만족하는 결과만 가져오지만,
DynamoDB에서는 페이지네이션을 통해 모든 데이터를 조회한 후 필터링하는 방식을 사용합니다.
FilterExpression 사용
아래는 FilterExpression을 사용해서 age가 25세 이상인 데이터를 조회하는 예제입니다.
import boto3
dynamodb = boto3.client("dynamodb", region_name="ap-northeast-2")
# 테이블명 설정
table_name = "Users"
# 페이지네이션 변수
limit = 2
last_evaluated_key = None
total_items = []
while True:
# Scan 요청 생성
scan_params = {
"TableName": table_name,
"Limit": limit,
"FilterExpression": "age >= :age",
"ExpressionAttributeValues": { ":age": {"N": "25"} } # 필터 조건
}
# 마지막 조회 위치가 있다면 추가
if last_evaluated_key:
scan_params["ExclusiveStartKey"] = last_evaluated_key
# Scan 실행
response = dynamodb.scan(**scan_params)
# 결과 추가
items = response.get("Items", [])
total_items.extend(items)
# 다음 페이지 확인
last_evaluated_key = response.get("LastEvaluatedKey")
# 모든 데이터 가져왔으면 종료
if not last_evaluated_key:
break
# 결과 출력
print(f"전체 데이터 개수: {len(total_items)}개")
KeyConditionExpression 사용
따라서 DynamoDB에서는 효율적인 필터링을 위해서
데이터를 가져온 후 필터링하는 "FilterExpression"가 아닌,
직접 DB에서 직접 필터링하는 "KeyConditionExpression"을 사용하는 것이 더 빠릅니다.
예제
import boto3
# DynamoDB 클라이언트 생성
dynamodb = boto3.client("dynamodb", region_name="ap-northeast-2")
# Query 실행
# PK(Partition Key) 및 SK(Sort Key)로 조회하는 query 사용 (scan보다 빠름)
response = dynamodb.query(
TableName="Users",
KeyConditionExpression="user_id = :uid",
ExpressionAttributeValues={":uid": {"S": "1234"}}
)
# 결과 출력
print(response["Items"])
다만 KeyConditionExpression을 사용하기 위해서는 필터링하려는 컬럼이
Partition Key (PK) 또는 Partition Key (PK) + Sort Key (SK) 조합이여야하는 조건이 있습니다.
Where절과 함께 Limit 사용
DynamoDB에서는 LIMIT이 WHERE보다 먼저 적용됩니다.
예를 들어
일반적인 SQL 데이터베이스(RDBMS)에서 아래의 쿼리는
WHERE 절로 먼저 필터링한 후, 결과 중에서 LIMIT 10을 적용합니다.
SELECT * FROM users WHERE age > 25 LIMIT 10;
반면에
DynamoDB에서의 동작 방식은 LIMIT을 적용한 후 FilterExpression을 평가합니다.
즉, 먼저 LIMIT 10개의 항목을 가져오고, 그 안에서 age > 25 필터를 적용합니다.
만약 LIMIT 10개 중 age > 25를 만족하는 항목이 2개라면, 실제 반환되는 데이터는 2개입니다.
response = table.scan(
FilterExpression=Attr("age").gt(25),
Limit=10
)
>>> 결과
[
{"user_id": "A123", "name": "John", "age": 30},
{"user_id": "B456", "name": "Alice", "age": 28}
]
내부적으로 LIMIT 수만큼 데이터를 가져온 후 필터링하기 때문에
필요한 데이터보다 적은 결과가 반환될 수 있으며, 추가 요청(페이지네이션)이 필요합니다.