| Query | Scan | |
|---|---|---|
| Input | PK (bắt buộc) + SK (optional) | Không cần key |
| Performance | Efficient — chỉ đọc matching items | Đọc TOÀN BỘ table |
| RCU | Chỉ tính cho matching items | Tính cho toàn bộ items scanned |
| Use case | Production queries | Analytics, migration, one-time jobs |
| Pagination | Tự động nếu > 1MB | Tự động nếu > 1MB |
import boto3
from boto3.dynamodb.conditions import Key
table = boto3.resource('dynamodb').Table('Orders')
# Query by PK + SK range
response = table.query(
KeyConditionExpression=Key('user_id').eq('user-123') &
Key('order_date').between('2025-01-01', '2025-12-31'),
ScanIndexForward=False, # Descending order
Limit=10
)
KeyConditionExpression: Filter trên PK và SK (TRƯỚC khi đọc)FilterExpression: Filter trên non-key attributes (SAU khi đọc)ScanIndexForward: True = ascending, False = descending (theo SK)ProjectionExpression: Chỉ lấy attributes cần thiết# Scan toàn bộ table (EXPENSIVE!)
response = table.scan(
FilterExpression=Attr('status').eq('active'),
ProjectionExpression='id, #n, email',
ExpressionAttributeNames={'#n': 'name'} # 'name' là reserved word
)
import concurrent.futures
def scan_segment(segment, total_segments):
return table.scan(
Segment=segment,
TotalSegments=total_segments,
FilterExpression=Attr('status').eq('active')
)
# Scan song song 4 segments
with concurrent.futures.ThreadPoolExecutor() as executor:
futures = [executor.submit(scan_segment, i, 4) for i in range(4)]
FilterExpression lọc SAU khi đọc → KHÔNG giảm RCU consumed. Luôn dùng Query thay vì Scan khi có thể. Nếu phải Scan, dùng ProjectionExpression để giảm data transfer.
Exam Tip: Query = efficient (dùng index). Scan = expensive (đọc hết). FilterExpression không giảm RCU. Cần query trên non-key attribute → tạo GSI.