Consistent reads are not supported on global secondary indexes

TL;DR — 你在一个针对全局二级索引的 QueryScan 上设置了 ConsistentRead: true。GSI 从基础表异步复制,只提供最终一致性读取——这个标志是一个硬性错误,而非偏好设置。去掉该标志,或者如果你确实需要写后读一致性,就读取基础表(或者把该键设计进一个 LSI)。

含义

ValidationException: Consistent reads are not supported on global secondary indexes

一个 GSI 在物理上是它自己的索引结构,有自己的分区和容量;DynamoDB 会把基础表的写入异步地传播进去。因为你刚写入的项目可能还没到达索引,DynamoDB 无法对它兑现一个强一致性读取——因此 ConsistentRead: true 与 GSI 的 IndexName 组合会被直接拒绝。AWS 文档说得很明确:用 ConsistentRead 设为 true 查询一个 GSI,你会收到 ValidationException

本地二级索引则不同:一个 LSI 与基础表共享其分区,因此那里支持 ConsistentRead: true

为什么会发生

  • 该标志被全局设置——一个共享的查询辅助工具或客户端封装为每次读取默认设置 ConsistentRead: true,而某条调用路径添加了一个指向 GSI 的 IndexName
  • 一个 LSI 变成了 GSI——为本地索引(那里该标志合法)编写的代码被指向了一个全局索引。
  • 复制粘贴的基础表查询——一个在表上合法地使用了强一致性的查询,被加上 IndexName 后重用了。

如何修复

  1. 从 GSI 读取中移除 ConsistentRead(或把它设为 false——默认值):

    await client.send(
      new QueryCommand({
        TableName: 'Orders',
        IndexName: 'status-index',
        KeyConditionExpression: '#s = :open',
        // ConsistentRead: true  ← delete this line for a GSI
        ExpressionAttributeNames: {'#s': 'status'},
        ExpressionAttributeValues: {':open': {S: 'OPEN'}}
      })
    );
  2. 需要写后读?ConsistentRead: true 查询基础表——只要你要查找的键是表自己的分区键,就可以做到。

  3. 相同的分区键,不同的排序? 把它建模为一个 LSI(在表创建时创建),它支持一致性读取。

  4. 或者在应用中吸收这个延迟——GSI 传播通常很快;对于 UI 流程,返回你已经拥有的刚写入的数据胜过重新读取索引。

DynoTable 桌面应用会显示每张表的索引并让你直接查询它们——而且因为它知道哪个索引是全局的、哪个是本地的,这类错误压根不会出现。

相关错误

References

最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。

无需控制台即可使用 DynamoDB

DynoTable 是面向 DynamoDB 的快速桌面客户端 —— 浏览表、运行 SQL 风格的查询,并在本地编辑项。