全局二级索引与本地二级索引
添加 GSI 和 LSI 以支持其他查询模式,而无需复制表。
全局二级索引与本地二级索引 是 CoddyKit 上的免费 AWS Solutions Architect 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 AWS Solutions Architect 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 AWS Solutions Architect 课程共包含 4 节课。
二级索引为何存在
DynamoDB 的主键定义了表中唯一高效的查询路径。如果您需要按照其他属性查询项目,例如在表的分区键为 CustomerId 时查找某个产品 ID 的所有订单,那么在没有二级索引的情况下,您必须执行开销很高的 Scan。
二级索引通过维护一份围绕不同键构建、自动更新的数据副本来解决这一问题。DynamoDB 提供两种类型:Global Secondary Indexes(GSI)和Local Secondary Indexes(LSI),二者各有不同的取舍。
Global Secondary Index(GSI)基础
Global Secondary Index允许您定义与基表完全不同的分区键(以及可选的排序键)。GSI 真正具有全局性,覆盖基表的所有分区。您可以通过查询 GSI,按照定义为 GSI 分区键的任意属性查找项目。
GSI 拥有独立于基表的预置吞吐量(或继承按需模式)。每个表最多可以创建 20 个 GSI,并且可以随时在现有表中添加或删除 GSI。
# Create a table with a GSI on ProductId
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=OrderId,AttributeType=S \
AttributeName=ProductId,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
--key-schema AttributeName=OrderId,KeyType=HASH \
--global-secondary-indexes '[
{
"IndexName": "ProductId-OrderDate-index",
"KeySchema": [
{"AttributeName": "ProductId", "KeyType": "HASH"},
{"AttributeName": "OrderDate", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"},
"ProvisionedThroughput": {"ReadCapacityUnits": 10, "WriteCapacityUnits": 5}
}
]' \
--provisioned-throughput ReadCapacityUnits=10,WriteCapacityUnits=5Local Secondary Index(LSI)基础
Local Secondary Index与基表共享同一个分区键,但使用不同的排序键。LSI 之所以称为“本地”,是因为它只能在单个分区内查询(即查询具有相同分区键的项目)。因此,LSI 非常适合按照不同属性对某个客户的订单进行排序查询。
LSI 必须在创建表时定义,之后无法添加或删除。每个表最多可以有 5 个 LSI。LSI 共享基表的预置容量(没有独立的吞吐量),并且基表与 LSI 数据的组合受每个分区键 10 GB 存储限制的约束。
# Create a table with an LSI (at creation time only)
aws dynamodb create-table \
--table-name Orders \
--attribute-definitions \
AttributeName=CustomerId,AttributeType=S \
AttributeName=OrderDate,AttributeType=S \
AttributeName=TotalAmount,AttributeType=N \
--key-schema \
AttributeName=CustomerId,KeyType=HASH \
AttributeName=OrderDate,KeyType=RANGE \
--local-secondary-indexes '[{
"IndexName": "TotalAmount-index",
"KeySchema": [
{"AttributeName": "CustomerId", "KeyType": "HASH"},
{"AttributeName": "TotalAmount", "KeyType": "RANGE"}
],
"Projection": {"ProjectionType": "ALL"}
}]' \
--billing-mode PAY_PER_REQUESTGSI 与 LSI:关键区别
以下是并列对比,便于备考时清晰理解:
- 分区键:GSI 可以与基表不同;LSI 必须与基表相同
- 排序键:两者都支持与基表不同的排序键
- 创建时间:GSI 可随时创建;LSI 只能在创建表时创建
- 吞吐量:GSI 拥有独立吞吐量;LSI 与基表共享吞吐量
- 一致性:GSI 只能进行最终一致性读取;LSI 支持强一致性读取
- 数量限制:最多 20 个 GSI;每个表最多 5 个 LSI
投影类型
创建索引时,您需要选择要投影(复制)到索引中的属性:
- KEYS_ONLY:仅包含基表主键和索引键——索引最小,但获取非键属性时需要额外调用 GetItem
- INCLUDE:包含键属性以及您指定的其他属性列表——在索引大小和访问模式之间取得平衡
- ALL:将所有属性投影到索引中——最灵活,但存储和写入成本更高
请根据查询实际需要的属性选择投影类型。投影过多会在每次写入时浪费写容量单位;投影过少则会迫使您额外调用 GetItem,以获取索引中未包含的属性。
查询 GSI
查询 GSI 使用相同的 Query API,但需要指定 --index-name 参数。查询会针对 GSI 的键架构执行,而不是针对基表的键架构执行。GSI 查询始终具有最终一致性——GSI 会在基表写入后异步更新,因此会存在短暂延迟。
如果基表中的某个项目没有 GSI 的分区键属性,则该项目完全不会被包含在 GSI 中(稀疏索引模式)。这是一种只为部分项目建立索引的强大技术,例如,当 GSI 分区键为 Status 时,只索引状态为 PENDING 的所有订单。
# Query the GSI for all orders for a product in 2026
aws dynamodb query \
--table-name Orders \
--index-name ProductId-OrderDate-index \
--key-condition-expression 'ProductId = :pid AND OrderDate BETWEEN :start AND :end' \
--expression-attribute-values \
'{":pid":{"S":"prod-abc"},":start":{"S":"2026-01-01"},":end":{"S":"2026-12-31"}}'稀疏索引模式
稀疏索引利用了这样一个事实:只有包含 GSI 分区键值的项目,DynamoDB 才会将其投影到 GSI 中。将 GSI 分区键定义在只有部分项目拥有的属性上,即可创建一个仅包含该子集项目的索引。
例如,在 Orders 表中,只有尚未发货的订单具有 PendingShipmentDate 属性。针对 PendingShipmentDate 创建 GSI 后,该索引自然只包含尚未发货的订单,因此无需扫描整个表,就能高效查询所有待处理订单。
使用 GSI 过载实现写入分片
GSI 过载是一种高级单表设计技术:您可以将不同实体类型存储在同一个表中,并使用通用的 GSI 键属性(例如 GSI1PK 和 GSI1SK),根据项目类型采用不同的模式填充值。这样,每种实体类型都能通过同一个 GSI 获得高效的查询路径。
例如,对于 User 项目,设置 GSI1PK = 'COUNTRY#US' 和 GSI1SK = username;对于 Order 项目,设置 GSI1PK = 'STATUS#PENDING' 和 GSI1SK = orderDate。使用相应的前缀查询 GSI,即可高效检索目标实体类型。
索引限流与容量
GSI 的限流独立于基表发生。如果为 GSI 预配的写容量单位过低,那么写入会投影到 GSI 中的项目时就会被限流——即使基表仍有充足容量也是如此。请分别监控每个 GSI 的 ConsumedWriteCapacityUnits 和 ThrottledRequests。
一个常见问题是为 GSI 配置的容量低于基表,之后写入模式突然导致 GSI 的写入速率增加,从而发生限流。请对 GSI 使用 Auto Scaling,或选择按需模式来避免此问题。
何时使用 GSI、LSI,还是重新设计
SAA-C03 考试中的决策指南:
- 需要按照完全不同的属性进行查询 → GSI
- 需要在同一分区内进行查询,但使用不同的排序方式,并且在创建时就已确定 → LSI
- 需要对备用排序键执行强一致性读取 → LSI(唯一选项,因为 GSI 只能提供最终一致性)
- 存在 10 种或更多不同的查询模式 → 考虑采用带 GSI 过载的单表设计,而不是创建许多独立表
- 只需要检索所有项目用于分析 → 重新考虑 DynamoDB 是否适合用作数据库
删除 GSI 与回填
您可以随时删除 GSI,而不会影响基表。向现有表添加新 GSI 时,DynamoDB 会通过扫描基表异步回填索引——对于大型表,这可能需要数分钟到数小时。回填期间,基表仍可完全进行读取和写入。
您可以在控制台中监控回填进度,也可以通过 DescribeTable API 检查索引的 IndexStatus 字段——回填期间该字段为 CREATING,完成后为 ACTIVE。在索引处于 ACTIVE 状态之前,请勿查询 GSI。
# Check GSI status during backfill
aws dynamodb describe-table \
--table-name Orders \
--query 'Table.GlobalSecondaryIndexes[*].{Name:IndexName,Status:IndexStatus}'快速检查
请测试您对本课 AWS Solutions Architect(SAA-C03)概念的理解。
课程回顾
本课介绍了:GSI 提供备用分区键,并且可以随时添加;LSI 与基表共享分区键,并且必须在创建时定义;以及投影类型决定哪些属性会被复制到索引中。GSI 还支持稀疏索引和过载模式,从而提供更灵活的高级查询能力。接下来,我们将学习 DynamoDB 流和全局表。
常见问题解答
「全局二级索引与本地二级索引」课时是免费的吗?
是的 — 「全局二级索引与本地二级索引」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 AWS Solutions Architect 课程的其余内容,请升级到 CoddyKit PRO。 AWS Solutions Architect 课程共包含 4 节课。
「全局二级索引与本地二级索引」这节课中我会学到什么?
添加 GSI 和 LSI 以支持其他查询模式,而无需复制表。 你通过在浏览器中直接运行的动手代码来练习 AWS Solutions Architect,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 AWS Solutions Architect 需要有经验吗?
无需任何先前经验。CoddyKit 上的 AWS Solutions Architect 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。
「全局二级索引与本地二级索引」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 AWS Solutions Architect 课中编写并运行代码吗?
能。每节 AWS Solutions Architect 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 表、项目与主键
- 预置容量与按需容量
- 全局二级索引与本地二级索引
- DynamoDB Streams 与全局表