DynamoDB 中的 GSI vs LSI
全局二级索引(GSI)和本地二级索引(LSI)都能让你用一个不是表键的属性来 Query。但它们不可互换——正是这些差异决定了某个模式该用哪一个。
DynamoDB 中 GSI 和 LSI 的区别是什么?
全局二级索引可以用任意顶层标量属性(字符串、数字或二进制)作为它的分区键,拥有自己独立的容量,可以随时添加——但只服务最终一致读取。本地二级索引沿用表相同的分区键、搭配一个不同的排序键,支持强一致读取并共享表的容量,但必须随表一起创建。
那些要紧的差异
| GSI | LSI | |
|---|---|---|
| 分区键 | 任意标量(S/N/B) | 与表相同 |
| 排序键 | 任意标量(S/N/B) | 任意标量(S/N/B) |
| 何时创建 | 随时 | 仅在建表时 |
| 一致性 | 仅最终一致 | 可用强一致 |
| 容量 | 独立拥有 | 共享表的 |
| 写入传播 | 异步(最终一致) | 同步(原子) |
| 每表上限 | 20(默认,可上调) | 5(硬性) |
| 10 GB 分区上限 | 无 | 有(每个 PK) |
一条经验法则
- 需要一个不同的(例如按
status而不是customer查订单)?你需要一个 GSI——LSI 无法重新分区。 - 需要在同一分区内换一种排序方式——LSI 沿用表精确的分区键、只换入一个不同的排序键——在建表时就已定下,并要求读取?那 LSI 合适。
这个选择归结为一个问题——你在改哪个键:
不同的分区键就逼着你用 GSI;在同一分区上换一个不同的排序键,是唯一适合 LSI 的情形。
实践中大多数团队几乎清一色地用 GSI:它们可以后加、独立伸缩,也不受 10 GB 每分区上限的约束。把单个 GSI 的键重载以服务多种模式——见单表设计。
如果你为了消灭一次 Scan 而添加一个 GSI,记住它有自己独立的读/写容量。用定价计算器来估算这份额外成本,并试用 DynoTable 在你锁定一个索引之前检视它的投影属性。