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'是这个结果。 我的印象是查询比扫描快得多(因为扫描需要对表进行整个迭代(。 此代码是否会导致数据库表的完整迭代?

这可能是一个单独的问题,但是是否有更有效的方法(带有代码示例(来执行此操作? 我尝试使用 Boto3 的分页,但我也无法处理查询。

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的回答标记为正确,因为正是他的回答导致了这个代码示例。

不幸的是,是的,"扫描"操作会读取整个表。你没有说表的分区键是什么,但如果它是一个日期,那么你在这里真正要做的是读取单个分区,这确实是"查询"操作更有效,因为它可以直接跳转到所需的分区,而不是扫描整个表寻找它。

即使使用 Query,您仍然需要像以前一样进行分页,因为分区仍有可能有很多项目。但至少您不会扫描整个表格。

顺便说一下,扫描整个表将花费您大量的读取操作。您可以询问 AWS 为您计算了多少次读取,这可以帮助您捕获读取过多的情况 - 除了您注意到的明显缓慢之外。

最新更新