在 DynamoDB 中使用扫描 - Amazon DynamoDB

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 DynamoDB 中使用扫描

AScan操作 Amazon DynamoDB 表或二级索引中的每个项目。默认情况下,Scan 操作返回表或索引中每个项目的全部数据属性。您可以使用 ProjectionExpression 参数,以便 Scan 仅返回部分属性而不是全部属性。

Scan 始终返回结果集。如果未找到匹配的项目,结果集将为空。

单个Scan请求最多可检索 1 MB 的数据。(可选)DynamoDB 可以向此数据应用筛选表达式,从而在将数据返回给用户之前缩小结果范围。

Scan 的筛选表达式

如果您需要进一步细化 Scan 结果,则可以选择性地提供筛选表达式。筛选表达式 可确定 Scan 结果中应返回给您的项目。所有其他结果将会丢弃。

筛选表达式在 Scan 已完成但结果尚未返回时应用。因此,无论是否存在筛选表达式,Scan 都将占用同等数量的读取容量。

AScan操作最多可检索 1 MB 的数据。此限制在计算筛选表达式之前应用。

Scan中,您可以在筛选表达式中指定任何属性 — 包括分区键和排序键属性。

筛选表达式的语法与条件表达式的相同。筛选表达式可使用的比较运算符、函数和逻辑运算符与条件表达式可使用的相同。有关更多信息,请参阅 条件表达式

以下 AWS Command Line Interface (AWS CLI) 示例将扫描 Thread 表,此时仅返回此表中由特定用户最新发布到的项目。

aws dynamodb scan \ --table-name Thread \ --filter-expression "LastPostedBy = :name" \ --expression-attribute-values '{":name":{"S":"User A"}}'

限制结果集中的项目数

Scan 操作可让您限制结果中返回的项目数。为此,将 Limit 参数设置为您在筛选条件表达式求值前希望 Scan 操作返回的最大项目数。

例如,假设您对某个表进行 ScanLimit 值为 6,并且没有筛选表达式。这些区域有:Scan结果将包含表中的前 6 个项目。

现在假设您向 Scan 添加了一个筛选表达式。在这种情况下,DynamoDB 将向返回的前 6 个项目应用筛选表达式,并放弃不匹配的项目。最终的 Scan 结果将包含 6 个或更少的项目,具体取决于筛选出的项目数。

为结果分页

DynamoDB分页结果来自Scan运算。通过分页,Scan结果将分成若干 “页” 大小为 1 MB(或更小)的数据。应用程序可以先处理第一页结果,然后处理第二页结果,依此类推。

单个Scan只会返回符合 1 MB 大小限制的结果集。要确定是否存在更多结果,并一次检索一页结果,应用程序应执行以下操作:

  1. 检查低级别 Scan 结果:

    • 如果结果包含 LastEvaluatedKey 元素,请继续步骤 2。

    • 如果结果中没有 LastEvaluatedKey,则表示没有其他要检索的项目。

  2. 构造新的 Scan 请求,使用与前一个请求相同的参数。但是,此次获取来自步骤 1 的 LastEvaluatedKey 值,并将其用作新 Scan 请求中的 ExclusiveStartKey 参数。

  3. 运行新的 Scan 请求。

  4. 前往步骤 1。

换言之,LastEvaluatedKey 响应中的 Scan 应该用作下一 ExclusiveStartKey 请求的 Scan。如果 Scan 响应中没有 LastEvaluatedKey 元素,则表示您已检索最后一页结果。(检查是否没有 LastEvaluatedKey 是确定您是否已到达结果集末尾的唯一方式。)

您可以使用 AWS CLI 查看此行为。这些区域有:AWS CLI发送低级别Scan请求,重复,直到LastEvaluatedKey不再出现在结果中。请考虑以下 AWS CLI 示例,它扫描整个 Movies 表,但仅返回特定流派的电影。

aws dynamodb scan \ --table-name Movies \ --projection-expression "title" \ --filter-expression 'contains(info.genres,:gen)' \ --expression-attribute-values '{":gen":{"S":"Sci-Fi"}}' \ --page-size 100 \ --debug

通常,AWS CLI 自动处理分页。但是,在此例中,AWS CLI --page-size 参数限制了每页项目数。--debug 参数输出有关请求和响应的低级别信息。

如果您运行该示例,DynamoDB 的首次响应类似如下内容。

2017-07-07 12:19:14,389 - MainThread - botocore.parsers - DEBUG - Response body: b'{"Count":7,"Items":[{"title":{"S":"Monster on the Campus"}},{"title":{"S":"+1"}}, {"title":{"S":"100 Degrees Below Zero"}},{"title":{"S":"About Time"}},{"title":{"S":"After Earth"}}, {"title":{"S":"Age of Dinosaurs"}},{"title":{"S":"Cloudy with a Chance of Meatballs 2"}}], "LastEvaluatedKey":{"year":{"N":"2013"},"title":{"S":"Curse of Chucky"}},"ScannedCount":100}'

响应中的 LastEvaluatedKey 指示并未检索所有项目。这些区域有:AWS CLI然后发出其他Scan请求到 DynamoDB。此请求和响应模式继续,直到收到最终响应。

2017-07-07 12:19:17,830 - MainThread - botocore.parsers - DEBUG - Response body: b'{"Count":1,"Items":[{"title":{"S":"WarGames"}}],"ScannedCount":6}'

如果不存在 LastEvaluatedKey,则表示没有其他要检索的项目。

注意

这些区域有:AWS开发工具包处理低级别的 DynamoDB 响应(包括是否存在LastEvaluatedKey),并为分页提供各种抽象Scan结果。例如,SDK for Java 发工具包文档界面提供java.util.Iterator支持,以便您能够一次处理一个结果。

有关各种编程语言的代码示例,请参阅Amazon DynamoDB 入门指南和AWS适用于您的语言的 SDK 文档。

对结果中的项目进行计数

除了与您的条件匹配的项目之外,Scan 响应还包含以下元素:

  • ScannedCount— 评估的项目数,在任何之前ScanFilter已应用。ScannedCount 值很高但 Count 结果很少或为零,指 Scan 操作效率低下。如果您没有在请求中使用筛选器,则 ScannedCountCount 相同。

  • Count— 剩余的项目数晚于将应用筛选表达式(如果有)。

注意

如果您不使用筛选表达式,那么 ScannedCountCount 将具有相同的值。

如果使用Scan结果集大于 1 MB,ScannedCountCount仅表示项目总数的部分计数。您需要执行多次 Scan 操作才能检索所有结果(请参阅为结果分页)。

所有 Scan 响应都将包含由该特定 Scan 请求处理的项目的 ScannedCountCount。要获取所有 Scan 请求的总和,您可以对 ScannedCountCount 记录流水账。

Scan 占用的容量单位

您可以Scan任何表或二级索引。Scan操作将占用读取容量单位,如下所示。

如果对...进行 Scan DynamoDB 将占用... 的读取容量单位
表的预置读取容量。
全局二级索引 索引的预置读取容量。
本地二级索引 基表的预置读取容量。

默认情况下,Scan 操作不会返回任何有关它占用的读取容量大小的数据。但是,您可在 ReturnConsumedCapacity 请求中指定 Scan 参数以获取此信息。下面是 ReturnConsumedCapacity 的有效设置:

  • NONE— 不返回任何已占用容量数据。(这是默认值。)

  • TOTAL— 响应包含占用的读取容量单位的总数。

  • INDEXES— 响应显示占用的读取容量单位的总数,以及访问的每个表和索引的占用容量。

DynamoDB 基于项目大小而不是返回到应用程序的数据量来确定占用的读取容量单位数。因此,无论您是请求所有属性(默认行为)还是只请求部分属性(使用投影表达式),占用的容量单位数都是相同的。无论您是否使用筛选表达式,该数量也是相同的。

Scan 的读取一致性

默认情况下,Scan 操作将执行最终一致性读取。这意味着 Scan 结果可能无法反映由最近完成的 PutItemUpdateItem 操作导致的更改。有关更多信息,请参阅读取一致性

如果您需要强一致性读取,请在 Scan 开始时在 ConsistentRead 请求中将 true 参数设置为 Scan。这可确保在 Scan 开始前完成的所有写入操作都会包括在 Scan 响应中。

设置ConsistentReadtrue可用于表备份或复制方案,与DynamoDB Streams。首先,您使用 Scan 并将 ConsistentRead 设置为 true 来获取表中数据的一致性副本。在Scan中,DynamoDB Streams 将记录表上发生的任何其他写入活动。在 Scan 完成后,您可以将流中的写入活动应用于该表。

注意

与保留 ConsistentRead 的默认值 (false) 相比,ConsistentRead 设置为 trueScan 操作将占用两倍的读取容量单位。

并行扫描

默认情况下,Scan操作按顺序处理数据。Amazon DynamoDB 以 1 MB 的增量向应用程序返回数据,并且应用程序执行其他Scan操作以检索下一个 1 MB 的数据。

扫描的表或索引越大,Scan需要完成。此外,一个顺序Scan可能并不总是能够充分使用预配置的读取吞吐量容量:即使 DynamoDB 跨多个物理分区分发大表的数据,Scan操作一次只能读取一个分区。出于这个原因,Scan会受到单个分区的最大吞吐量限制。

为了解决这些问题,Scan操作可以逻辑上将表或二级索引分成多个分段,多个应用程序工作人员并行扫描这些段。每个工作线程可以是一个线程(在支持多线程的编程语言中),也可以是一个操作系统进程。要执行并行扫描,每个工作程序都会发出自己的Scan使用以下参数:

  • Segment— 要由特定工作人员扫描的段。每个工作人员应使用不同的值Segment

  • TotalSegments— 并行扫描的片段总数。该值必须与您的应用程序将使用的工作线程数相同。

下图显示了多线程应用程序如何执行并行Scan具有三个并行度。

在此图中,应用程序生成三个线程,并为每个线程分配一个数字。段从零开始,因此,第一个数字始终为 0。) 每个线程都会发出Scan请求,设置Segment设置为其指定的编号并将TotalSegments设置为 3。每个线程扫描其指定的段,每次检索 1 MB 的数据,并将数据返回到应用程序的主线程。

使用的值SegmentTotalSegments适用于单个Scan请求,并且您可以随时使用不同的值。您可能需要对这些值以及您使用的工作线程数进行试验,直到您的应用程序达到最佳性能。

注意

具有大量工作程序的并行扫描可以轻松占用正在扫描的表或索引的所有预配置吞吐量。如果表或索引也引起来自其他应用程序的大量读取或写入活动,最好避免进行此类扫描。

要控制每个请求返回的数据量,请使用Limit参数。这有助于防止出现一个工作程序占用所有预配置吞吐量而牺牲所有其他工作程序的情况。