为订单状态添加索引

AWSBeginner
立即练习

介绍

打包团队需要跨客户获取 NEW 订单。客户与日期主键无法通过一次基础表 Query 满足这个访问模式。你将添加全局二级索引,选择投影,查询实际队列,并观察基础表写入后已打包订单如何在索引分区间移动。

请先完成“使用分区键和排序键查询订单”。这个全新 VM 只准备基础表、合成记录、参考表和应用框架。创建索引及配置查询由你完成。使用 /home/labex/project、官方 AWS CLI 和 AWS View。

认证考点

认证 考点 本实验练习
Solutions Architect – Associate (SAA-C03) 任务 3.3 DynamoDB 二级索引与属性投影。
Developer – Associate (DVA-C02) 任务 1.3 DynamoDB 二级索引与属性投影。
Data Engineer – Associate (DEA-C01) 任务 2.4 基础练习:DynamoDB 二级索引与属性投影。

实验概览

使用 AWS4 图标并由 draw.io 导出的概念图:GSI 为同一批订单提供状态和日期视图,支持跨客户的 NEW 待处理订单列表;基础表写入会更新这一派生视图。

添加替代访问模式

在本步骤中,你将为需要跨客户获取 NEW 订单的打包队列添加索引。已准备好的表使用 customer_id 和 order_key;基础表 Query 无法按状态选择全部客户,因为 status 不是分区键。全局二级索引(GSI)为相同项目提供另一种分区键与排序键视图。

客户查询和打包队列围绕同一批订单回答不同的业务问题。GSI 让队列直接选择跨客户的状态分区。在客户 Query 中添加状态过滤器仍只会检查该客户的分区,不能创建队列所需的另一条访问路径。

相同项目中的选定属性,分别按基础表键和状态索引键排列。

订单表和三个合成记录已独立准备好,让你专注于新访问模式。先查看它们;除本实验教授的状态更新外,保持全部记录不变。

cd /home/labex/project
aws dynamodb describe-table --table-name labex-d03-orders --query 'Table.KeySchema'
aws dynamodb scan --table-name labex-d03-orders --consistent-read

添加 StatusDateIndex,以 status 为分区键,order_key 为排序键。投影(projection)决定索引存储哪些属性。INCLUDE 添加 amount;表键和索引键自动包含。非键 source 属性只保留在基础表中。在 AWS 上,索引存储和写入产生费用。

aws dynamodb update-table \
  --table-name labex-d03-orders \
  --attribute-definitions AttributeName=status,AttributeType=S AttributeName=order_key,AttributeType=S \
  --global-secondary-index-updates '[{"Create":{"IndexName":"StatusDateIndex","KeySchema":[{"AttributeName":"status","KeyType":"HASH"},{"AttributeName":"order_key","KeyType":"RANGE"}],"Projection":{"ProjectionType":"INCLUDE","NonKeyAttributes":["amount"]}}}]'
aws dynamodb describe-table \
  --table-name labex-d03-orders \
  --query 'Table.GlobalSecondaryIndexes[].{Name:IndexName,State:IndexStatus,Keys:KeySchema,Projection:Projection}'

只在 StatusDateIndex 报告 ACTIVE 后继续。在 AWS 上,创建可能需要时间;索引仍在创建时,重复 describe 命令。table-exists 等待器不能证明新索引就绪。服务报告索引后,AWS View 在表卡片内显示它。

查询状态索引并查看投影

在本步骤中,你将通过替代键读取 NEW 队列。--index-name 选择 GSI。键条件使用状态相等;基础表扫描中的过滤会先读取无关项目。

aws dynamodb query \
  --table-name labex-d03-orders \
  --index-name StatusDateIndex \
  --key-condition-expression '#state = :state' \
  --expression-attribute-names '{"#state":"status"}' \
  --expression-attribute-values '{":state":{"S":"NEW"}}'

索引返回 Ada 的 O100 和 Bob 的 O200,各自包含 amount。source 属性不存在,因为没有投影。获取额外基础表属性需要独立的按键读取。

在 AWS 上,GSI 更新是异步的,GSI 读取采用最终一致性。不要为 GSI Query 添加 --consistent-read:该请求会以 ValidationException 被拒绝。如果近期写入尚未到达索引,应等待并重复读取;不要将旧结果视为写入失败的证据。

上一个实验提供的 order-lookup 应用读取普通 lookup.json 设置。编写请求,选择这个索引和 NEW 队列。带引号的 heredoc 原样写入 JSON;ConsistentRead: false 明确索引读取选择。

cat > lookup.json <<'JSON'
{
  "paginate": true,
  "request": {
    "TableName": "labex-d03-orders",
    "IndexName": "StatusDateIndex",
    "KeyConditionExpression": "#state = :state",
    "ExpressionAttributeNames": {
      "#state": "status"
    },
    "ExpressionAttributeValues": {
      ":state": {
        "S": "NEW"
      }
    },
    "ConsistentRead": false
  }
}
JSON
./order-lookup

应用返回相同两个订单。在 AWS View 中展开 StatusDateIndex,将实际投影与查询结果比较。状态队列包含两个客户是正确的,而针对单个客户的视图需要另一种键模式。

观察订单在状态队列间移动

在本步骤中,你将把 O100 标记为已打包,并观察索引条目移动。GSI 跟随基础表写入;你不直接写入索引。更新 status 改变项目的索引分区,而基础主键保持相同。

aws dynamodb update-item \
  --table-name labex-d03-orders \
  --key '{"customer_id":{"S":"ada"},"order_key":{"S":"2026-10-01#O100"}}' \
  --update-expression 'SET #state = :state' \
  --expression-attribute-names '{"#state":"status"}' \
  --expression-attribute-values '{":state":{"S":"PACKED"}}' \
  --return-values ALL_NEW
./order-lookup

NEW 队列现在只包含 Bob 的 O200。查询 PACKED,确认 O100 与 O101 一起出现,而非从服务中消失。

aws dynamodb query \
  --table-name labex-d03-orders \
  --index-name StatusDateIndex \
  --key-condition-expression '#state = :state' \
  --expression-attribute-names '{"#state":"status"}' \
  --expression-attribute-values '{":state":{"S":"PACKED"}}'

预期 PACKED 中包含 Ada 的 O100 和 O101。在 AWS 上,重复这些读取直到索引传播可见。更新响应和一致性基础表读取是权威的即时项目状态;GSI 是最终一致的派生视图。AWS View 显示 O100 的新状态,以及只包含 O200 的 NEW 查询结果。

活动索引投影替代键和 amount,NEW 队列只包含 Bob 的订单。

删除自己的索引和表

在本步骤中,你将删除替代视图,再删除练习表。删除索引保留基础表项目;删除表移除项目及剩余索引。只指定自己的资源。

aws dynamodb update-table \
  --table-name labex-d03-orders \
  --global-secondary-index-updates '[{"Delete":{"IndexName":"StatusDateIndex"}}]'
aws dynamodb describe-table \
  --table-name labex-d03-orders \
  --query 'Table.GlobalSecondaryIndexes'

索引列表为空后继续。在 AWS 上,删除进行中时重复 DescribeTable。此时表仍有三个项目。

aws dynamodb scan --table-name labex-d03-orders --consistent-read --select COUNT
aws dynamodb delete-table --table-name labex-d03-orders
aws dynamodb wait table-not-exists --table-name labex-d03-orders
aws dynamodb list-tables
aws dynamodb get-item \
  --table-name labex-d03-reference \
  --key '{"id":{"S":"platform"}}' \
  --consistent-read

订单表及索引不存在;参考 note 仍为 keep unchanged。成功清单查询和参考读取区分清理与服务断开。AWS View 只保留无关参考资源。一次性连接随 VM 结束。

总结

你为跨客户状态队列添加了 GSI,选择投影属性,并在实际查询中使用索引键。基础表状态更新使订单在索引分区间移动,而主键不变。你区分了即时基础表状态与最终索引传播,再只删除自己的索引和表。

进一步阅读 AWS 官方资料:全局二级索引、投影与一致性。