Amazon DynamoDB
开发人员指南 (API 版本 2012-08-10)
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

使用扫描

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

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

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

Scan 的筛选表达式

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

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

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

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

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

以下 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. 使用与上一个 Query 请求相同的参数构造新的 Scan 请求 — 但此次,请选取步骤 1 中的 LastEvaluatedKey 值并将其用作新的 Scan 请求中的 ExclusiveStartKey 参数。

  3. 运行新的 Scan 请求。

  4. 前往步骤 1。

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

您可以使用 AWS CLI 查看此行为。CLI 向 DynamoDB 反复发送低级别 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 将自动处理分页;但在此示例中,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 结果进行分页。例如,适用于 Java 的开发工具包 文档接口提供 java.util.Iterator 支持,以便您能够一次处理一个结果。

对于各种编程语言的代码示例,请参阅本地化的 Amazon DynamoDB 入门指南 和 AWS 开发工具包文档。

对结果中的项目进行计数

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

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

  • Count — 在应用筛选表达式(如果有)之后,剩余的项目的数量。

注意

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

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

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

Scan 占用的容量单位

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

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

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

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

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

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

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

Scan 的读取一致性

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

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

在表备份或复制方案中,将 ConsistentRead 设置为 trueDynamoDB 流结合使用可能很有用:首先使用 ConsistentRead 设置为 true 的 Scan,以获取表中数据的一致副本。Scan 操作期间,DynamoDB 流 会记录表上发生的任何其他写入活动。在 Scan 操作完成后,您可以将流中的写入活动应用于该表。

注意

请注意,与保留 Scan 的默认值 (ConsistentRead) 相比,true 设置为 ConsistentReadfalse 操作将占用两倍的读取容量单位。

并行扫描

默认情况下,Scan 操作会按顺序处理数据。DynamoDB 会按 1 MB 的增量向应用程序返回数据,并且应用程序会再执行 Scan 操作来检索接下来的 1 MB 数据。

要扫描的表或索引越大,完成 Scan 所需的时间越多。此外,顺序 Scan 未必能够完全利用预配置读取吞吐容量:即使 DynamoDB 将大型表的数据分布到多个物理分区,Scan 操作也只能一次读取一个分区。因此,Scan 的吞吐量受单个分区的最大吞吐量约束。

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

  • Segment — – 由特定工作线程扫描的分段。每个工作线程应使用不同的 Segment 值。

  • TotalSegments — – 并行扫描要处理的分段总数。此值必须与应用程序使用的工作线程数相同。

以下图表显示了多线程应用程序如何执行并行度为 3 的并行 Scan 操作:

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

SegmentTotalSegments 的值会应用到各个 Scan 请求,您随时可以使用不同的值。您可能需要不断尝试这些值以及所使用的工作线程数量,直到应用程序性能达到最佳。

注意

使用大量工作线程进行的并行扫描可轻松占用要扫描的表或索引的所有预置吞吐量。如果表或索引同时产生来自其他应用程序的大量读取或写入活动,则最好是避免使用此类扫描。

要控制每个请求返回的数据量,请使用 Limit 参数。这样可有助于防止一个工作线程用尽所有预置吞吐量,所有其他工作线程都没有吞吐量可用的情况。