入门阅读约 3 分钟

如何按降序查询 DynamoDB

默认情况下,一次 DynamoDB Query 按排序键的升序返回条目。但大多数"给我最新的"访问模式想要的恰恰相反——最新在前。旋钮是 Query 上的一个布尔值:ScanIndexForward。把它设为 false,同一个查询就会反向读取分区。

它只是一个参数,但它绊倒了不少人,因为它容易和事后对_结果_排序(DynamoDB 并不做这件事)混淆,也因为这个名字读起来跟它控制的东西是反的。

我该怎么按降序查询 DynamoDB?

Query 上设置 ScanIndexForward=false。默认情况下 DynamoDB 按排序键升序返回条目;翻转这一个布尔值会反向读取分区,当你的排序键是时间戳或序列时,就给你最新在前的结果。它只改变排序,不改变哪些条目匹配,而且反向读取的成本与正向的完全相同。

  • ScanIndexForward=true(默认) → 排序键升序。
  • ScanIndexForward=false → 降序——当你的排序键是时间戳或序列时,即最新在前。
  • 它只影响排序,不影响哪些条目匹配——那仍由键条件决定。
  • 它是免费的。反向排序的成本与正向相同;DynamoDB 无论哪种方式都读取分区已存储的顺序。
  • 配合 Limit 使用,在一次便宜的读取里拿到"最近的 N 个"。

问题:"先给我看最新的"

假设你运营一个多人排行榜,把每个玩家的得分事件存在一个分区键下,按递增的时间戳排序:

PK: GAME#42   SK: SCORE#2026-06-27T10:00:00Z   points
PK: GAME#42   SK: SCORE#2026-06-27T10:05:00Z   points
PK: GAME#42   SK: SCORE#2026-06-27T10:09:00Z   points

仪表盘需要最近的得分。一次对 GAME#42 的普通 Query 会最旧在前地返回它们,所以你会忍不住想读取全部再在应用里翻转——既浪费,又在你一加 Limit 的那一刻就出错。DynamoDB 能直接把它们最新在前地交还给你。

ScanIndexForward 如何运作

一个分区里的条目在物理上按排序键有序存储。一次 Query 走过那个顺序;ScanIndexForward 只是挑选行走的方向:

  • true(默认)——从最低的排序键起步,向上走(升序)。
  • false ——从最高的排序键起步,向下走(降序)。

关键在于,这是读取的属性,而不是表的——相同的条目、相同的键条件,只是反了过来。而且因为 DynamoDB 只是在已经排好序的数据上选一个方向,降序读取与升序读取一样便宜。把它和 Limit=10 搭配,你就在一次单一、最低成本的 Query 里拿到"最近的 10 个得分事件"。

true(默认)falseQuery GAME#42ScanIndexForward?最旧的得分在前最新的得分在前

一个微妙之处:当你在一个降序结果集里向后分页时,LastEvaluatedKey/ExclusiveStartKey 游标仍然有效——只要在同一个查询的每一页上都保持 ScanIndexForward=false 一致,否则游标方向和顺序就会打架。

在 DynoTable 中构建这个查询

要组装键条件本身(并看到匹配的属性名/值映射),用 DynamoDB 表达式构建器。至于整个请求——包括索引、LimitScanIndexForward——查询构建器会组装这个 Query,并输出可运行的 SDK v3、CLI 或 boto3 程序。

在 DynoTable 里,你通过一个选定的键读取一个标签页,并用一个开关在标签页上设置排序方向——无需手写 ScanIndexForward。翻转它就能预览最新在前的结果。

在 DynoTable 中把一个查询标签页切换为降序(最新在前)排序。
在 DynoTable 中把一个查询标签页切换为降序(最新在前)排序。

陷阱与后续步骤

  • ScanIndexForward 是反转,不是按任意属性排序。顺序永远是按排序键的——要按别的东西排序,你需要把那个属性_作为_排序键(通常通过一个 GSI)。
  • 别在应用里读取全部再翻转——设置这个标志并加上 Limit
  • 分页时保持标志一致,在一个多页查询里,否则游标会和顺序对着干。
  • 想要数值型的最新在前?一个 Number 类型的排序键已经按数值排序了。只有当你把数字嵌进了一个字符串排序键里时,你才需要给它们补零,好让字典序与之匹配。
  • 相关阅读:排序键策略分页

想不碰 API 参数就翻转结果顺序?下载 DynoTable,直接查询你的表。

复合和数字排序键

降序遵循排序键类型规则,而不是您的心理模型 “最新”:

排序键存储为降序给你问题
ISO-8601 UTC 字符串 2026-06-27T10:09:00Z最新时间戳优先当时区固定时,字典顺序与时间顺序匹配
零填充纪元字符串 00000000001009最高序列优先未填充的数字排序错误 ("9" > "10") — 请参阅zero-padding
数字类型N最大的数值在前自然数字顺序,而不是字符串
状态前缀STATUS#open#...完整 SK 上的反向字典顺序与“最近打开”不同,除非在后缀
points 在同一个游戏分区内 - 您需要在排序中使用该指标
key (或者在排序键为 points 的 GSI 上),而不是查询后排序应用程序代码。

Limit 降序读取

Limit 限制评估的项目,而不是过滤后返回的项目。配对 ScanIndexForward=falseLimit=10 在按时间排序的排序键上以获取读取一个分区中的十个最近事件。成本示例:10 个 2 KB 项目按降序排列 Query 触摸 20 KB → 3 最终一致的 RCU(四舍五入到 4 KB 块)。读取整个分区应用程序代码中要反转的 10,000 个事件涉及约 20 MB → 数千个 RCU 用于相同的 UI 小部件。为您的分区大小建模选择前item-size calculator Limit

分页保持方向性

当您使用 ExclusiveStartKey 寻呼时,请保持 ScanIndexForward 相同每一个请求。在页面之间翻转标志会反转光标语义 - 您可以跳过或重复行。对于公开“加载更多”的 API,对 LastEvaluatedKey 进行不透明的 Base64 编码;客户端不应改变排序键组件。参见 pagination 用于标记模式。

PartiQL与SDK比价

PartiQL ExecuteStatement 查询通过以下方式接受相同的排序语义当执行器映射到关键条件读取时,底层Query参数。 query builder 发出 SDK v3、CLI 或 boto3 显式连接 ScanIndexForward 的程序 — 当您的团队混合时很有帮助 PartiQL 使用生产 SDK 代码进行即席查询。

使用降序的访问模式

  • 活动提要SK 是 ISO 时间戳;降序 + Limit 产生最近的窗口。
  • 排行榜 — 数字排序键 score;下降表面最高分当分区键范围为一场比赛或一个赛季时。
  • 审核尾部 — 仅附加 EVENT#<ts> 排序键;降序显示最新首先是没有 GSI 的事件。当UI还需要升序历史记录(“首先显示最旧的”)时,相同的查询使用 ScanIndexForward=true 可以避免重复数据或维护两个索引。

尝试切换真实数据

连接DynoTable,使用按时间排序的排序键在分区上打开查询选项卡,升序/降序翻转,无需编辑即可观看网格重新排序API 参数。比较操作日志中消耗的容量——前进和后退相同 Limit 上的反向读取应该匹配。

更新于