DynamoDB Python 分页查询(非扫描)
DynamoDB Python Query with Pagination (not scan)
我正在使用以下代码通过 DynamoDB 查询进行查询和分页:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
def run(date: int, start_epoch: int, end_epoch: int):
dynamodb = boto3.resource('dynamodb',
region_name='REGION',
config=Config(proxies={'https': 'PROXYIP'}))
table = dynamodb.Table('XYZ')
response = table.query(
# ProjectionExpression="#yr, title, info.genres, info.actors[0]", #THIS IS A SELECT STATEMENT
# ExpressionAttributeNames={"#yr": "year"}, #SELECT STATEMENT RENAME
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
)
for i in response[u'Items']:
print(json.dumps(i, cls=DecimalEncoder))
while 'LastEvaluatedKey' in response:
response = table.scan( ##IS THIS INEFFICIENT CODE?
# ProjectionExpression=pe,
# FilterExpression=fe,
# ExpressionAttributeNames=ean,
ExclusiveStartKey=response['LastEvaluatedKey']
)
for i in response['Items']:
print(json.dumps(i, cls=DecimalEncoder))
尽管此代码有效,但速度非常慢,我担心“response = table.scan
”是此代码的结果。我的印象是查询比扫描快得多(因为扫描需要 table 的整个迭代)。此代码是否导致数据库的完整迭代 table?
这可能是一个单独的问题,但是是否有更有效的方法(带有代码示例)来执行此操作?我尝试过使用 Boto3 的分页,但我也无法使用查询。
不幸的是,是的,"Scan" 操作会读取整个 table。你没有说你的 table 的分区键是什么,但如果它是一个日期,那么你在这里真正做的是读取单个分区,这确实是 "Query"操作效率更高,因为它可以直接跳转到所需的分区,而不是扫描整个 table 寻找它。
即使使用Query,您仍然需要像以前一样进行分页,因为分区中可能还有很多项目。但至少你不会扫描整个 table.
顺便说一下,扫描整个table会消耗你很多读取操作。您可以询问 AWS 为您计算了多少次读取,这可以帮助您发现读取过多的情况 - 除了您注意到的明显缓慢之外。
Nadav Har'El 提供的答案是解决此问题的关键。我通过执行初始 DynamoDB 查询错误地使用了 DynamoDB 分页代码示例,但随后使用扫描进行分页!
正确的方法是最初使用查询并进行分页:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
def run(date: int, start_epoch: int, end_epoch: int):
dynamodb = boto3.resource('dynamodb',
region_name='REGION',
config=Config(proxies={'https': 'PROXYIP'}))
table = dynamodb.Table('XYZ')
response = table.query(
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
)
for i in response[u'Items']:
print(json.dumps(i, cls=DecimalEncoder))
while 'LastEvaluatedKey' in response:
response = table.query(
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch),
ExclusiveStartKey=response['LastEvaluatedKey']
)
for i in response['Items']:
print(json.dumps(i, cls=DecimalEncoder))
我仍然将 Nadav Har'El 的回答标记为正确,因为正是他的回答导致了这个代码示例。
我正在使用以下代码通过 DynamoDB 查询进行查询和分页:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
def run(date: int, start_epoch: int, end_epoch: int):
dynamodb = boto3.resource('dynamodb',
region_name='REGION',
config=Config(proxies={'https': 'PROXYIP'}))
table = dynamodb.Table('XYZ')
response = table.query(
# ProjectionExpression="#yr, title, info.genres, info.actors[0]", #THIS IS A SELECT STATEMENT
# ExpressionAttributeNames={"#yr": "year"}, #SELECT STATEMENT RENAME
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
)
for i in response[u'Items']:
print(json.dumps(i, cls=DecimalEncoder))
while 'LastEvaluatedKey' in response:
response = table.scan( ##IS THIS INEFFICIENT CODE?
# ProjectionExpression=pe,
# FilterExpression=fe,
# ExpressionAttributeNames=ean,
ExclusiveStartKey=response['LastEvaluatedKey']
)
for i in response['Items']:
print(json.dumps(i, cls=DecimalEncoder))
尽管此代码有效,但速度非常慢,我担心“response = table.scan
”是此代码的结果。我的印象是查询比扫描快得多(因为扫描需要 table 的整个迭代)。此代码是否导致数据库的完整迭代 table?
这可能是一个单独的问题,但是是否有更有效的方法(带有代码示例)来执行此操作?我尝试过使用 Boto3 的分页,但我也无法使用查询。
不幸的是,是的,"Scan" 操作会读取整个 table。你没有说你的 table 的分区键是什么,但如果它是一个日期,那么你在这里真正做的是读取单个分区,这确实是 "Query"操作效率更高,因为它可以直接跳转到所需的分区,而不是扫描整个 table 寻找它。
即使使用Query,您仍然需要像以前一样进行分页,因为分区中可能还有很多项目。但至少你不会扫描整个 table.
顺便说一下,扫描整个table会消耗你很多读取操作。您可以询问 AWS 为您计算了多少次读取,这可以帮助您发现读取过多的情况 - 除了您注意到的明显缓慢之外。
Nadav Har'El 提供的答案是解决此问题的关键。我通过执行初始 DynamoDB 查询错误地使用了 DynamoDB 分页代码示例,但随后使用扫描进行分页!
正确的方法是最初使用查询并进行分页:
class DecimalEncoder(json.JSONEncoder):
def default(self, o):
if isinstance(o, decimal.Decimal):
return str(o)
return super(DecimalEncoder, self).default(o)
def run(date: int, start_epoch: int, end_epoch: int):
dynamodb = boto3.resource('dynamodb',
region_name='REGION',
config=Config(proxies={'https': 'PROXYIP'}))
table = dynamodb.Table('XYZ')
response = table.query(
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch)
)
for i in response[u'Items']:
print(json.dumps(i, cls=DecimalEncoder))
while 'LastEvaluatedKey' in response:
response = table.query(
KeyConditionExpression=Key('date').eq(date) & Key('uid').between(start_epoch, end_epoch),
ExclusiveStartKey=response['LastEvaluatedKey']
)
for i in response['Items']:
print(json.dumps(i, cls=DecimalEncoder))
我仍然将 Nadav Har'El 的回答标记为正确,因为正是他的回答导致了这个代码示例。