1.3.3 Query vs Scan

Query vs Scan Operations

So sánh

QueryScan
InputPK (bắt buộc) + SK (optional)Không cần key
PerformanceEfficient — chỉ đọc matching itemsĐọc TOÀN BỘ table
RCUChỉ tính cho matching itemsTính cho toàn bộ items scanned
Use caseProduction queriesAnalytics, migration, one-time jobs
PaginationTự động nếu > 1MBTự động nếu > 1MB

Query

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

# 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
)

Parallel Scan

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)]
  • Chia table thành segments, scan song song
  • Nhanh hơn nhưng tốn nhiều RCU hơn

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.