【问题标题】:DynamoDB Python Query with Pagination (not scan)DynamoDB Python 查询与分页(非扫描)
【发布时间】:2022-02-03 07:14:00
【问题描述】:

我正在使用以下代码通过 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 的分页,但我也无法使用查询。

【问题讨论】:

    标签: amazon-web-services amazon-dynamodb dynamodb-queries


    【解决方案1】:

    Nadav Har'El 提供的答案是解决此问题的关键。我通过执行初始 DynamoDB 查询错误地使用了 DynamoDB 分页代码示例,但随后使用扫描进行分页!

    正确的方法是最初使用查询 AND 进行分页:

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

    【讨论】:

      【解决方案2】:

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

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

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

      【讨论】:

      • 我想尽可能快地进行此查询,并且我知道我的数据集将大于 DynamoDB 的 1MB API 限制,因此我将不得不使用分页。我想确认我的分页代码是最有效的方法——因为它真的很慢。我上面的代码使用了一个使用日期分区的初始查询,但随后对分页使用了扫描查询......分页的扫描查询是这样做的唯一方法吗?
      • 不,正如我所说,“查询”比“扫描”更好。 “扫描”始终读取整个数据库,而“查询”仅读取一个分区(也可能很长,因此您还需要对其进行分页)。请查阅有关“扫描”和“查询”操作之间区别的文档。
      • 我在下面添加了我的代码答案。我的问题是我没有意识到您可以使用 table.query 进行分页,因为我发现的代码示例使用了 table.scan。这应该可以解决我的问题。我在下面添加了我的代码作为答案。
      猜你喜欢
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多