入门阅读约 3 分钟

DynamoDB 复合主键

复合主键是两个属性:一个分区键和一个排序键。分区键决定一个项住在哪里;排序键给那个分区内部的各项排序。

从 SQL 过来,与其把它想成一个唯一的 id 列,不如把它想成 GROUP BY partition, ORDER BY sort 被烤进了表本身。

什么是 DynamoDB 复合主键?

DynamoDB 复合主键由两个属性组成:一个分区键和一个排序键。分区键决定一个项存放在哪个物理分区中;排序键给那个分区内部的各项排序。两者共同构成项的唯一标识,并让一次 Query 返回一个排好序的范围,而非单个项。

  • 两部分,两份活。 分区键把项路由到一个物理分区;排序键给共享那个分区键的每一个项排序。
  • 唯一性是这一对。 只要排序键不同,两个项就可以共享一个分区键值 —— 这就是一个分区如何容纳许多行。
  • 排序键是整个要点。 是它让一次 Query 返回一个范围(>=betweenbegins_with)而非一个项,且不需 Scan
  • 键必须是标量。 分区键和排序键只能是字符串、数字或二进制 —— 没有映射,没有列表(AWS 文档)。

简单键 vs 复合键

一个简单主键就只是一个分区键。它唯一地标识一个项,而你用 GetItem 把它读回来。仅此而已 —— 没有范围读取,没有“给我最新的 N 个”。

复合键加上排序键,而那单单一项添加,就是让 DynamoDB 感觉像个数据库、而非一张哈希表的东西。

简单键复合键
属性仅分区键分区键 + 排序键
唯一性分区键值这两个值组成的
每分区多项
Query 一个范围否(仅 GetItem是(begins_withbetween>
天然适配按 id 查找时间序列、一对多、历史

给传感器读数表建模

假设你从一批现场传感器收集温度采样。访问模式是“在一个时间窗口内,取某个设备的读数,最新优先”。那是教科书式的复合键。

用设备 id 作分区键、读数时间戳作排序键

deviceIdreadingTstempChumidity
DEV#a1b22026-06-23T08:00:00Z21.448
DEV#a1b22026-06-23T08:05:00Z21.747
DEV#a1b22026-06-23T08:10:00Z22.146
DEV#c9d82026-06-23T08:00:00Z19.855

全部三个 DEV#a1b2 读数都落在同一个分区,物理上存在一起,并按 readingTs 排序。

AWS 把分区键叫做 哈希属性、把排序键叫做 范围属性 —— 排序键是一个你能在其内部扫描的范围(AWS 文档)。

下面是各项如何在每个分区键之下坍缩成一个项集合:

分区:DEV#a1b2readingTs 08:00readingTs 08:05readingTs 08:10Query deviceId = DEV#a1b2

对分区键的一次 Query 读取那个设备的每一条读数,已经按时间戳排好序 —— 客户端无需排序,无需第二次往返。

查询那个范围,别扫描它

因为 readingTs 是一个 ISO-8601 字符串,它按字典序排序的方式与按时间顺序排序的方式相同。所以一次时间窗口读取是一个键条件范围,而非一个筛选:

Query
deviceId  = "DEV#a1b2"
readingTs BETWEEN "2026-06-23T08:00:00Z" AND "2026-06-23T08:10:00Z"

那是一个 KeyConditionExpression —— 它在 DynamoDB 返回数据 之前 缩小读取,所以你只为窗口内的项付费。一个 FilterExpression 在读取 之后 运行,并就它扫过的一切向你计费;那是缩小版的 Scan 暗坑

表达式本身,连同占位符和带类型的值,手写起来很麻烦。用 DynamoDB 表达式构建器可视化地构建它,并把精确的 KeyConditionExpression 拷进你的 SDK 调用。

有意地设计排序键

排序键不是免费的元数据 —— 它是范围读取的唯一杠杆,所以把它塑造成贴合你的查询。

  • 用一个可排序的时间戳。 ISO-8601 字符串或补零的纪元数字排序正确;原始的本地化日期不行。
  • 给它加前缀以做一对多重载。 一个像 READING#2026-06-23T08:00:00Z 的排序键让你在一个分区下混合实体类型,并用 begins_with 切分它们。那是通向单表设计的接缝。
  • 把高基数维度放进分区键。 传感器 id 有数千个值,所以它均匀地分散写入。一个低基数分区键(比如 region)会造出一个热分区。

复合键何时咬你

它是一项承诺,而非一项便利。陷阱:你挑了一个分区键、上线了,然后发现一个需要 不同 分组的访问模式 —— “整个机队里所有高于 30°C 的读数”。

基表回答不了那个;分区键是固定的。你的选项是一个带不同键的全局二级索引,或者重构。

在你提交键模式 之前 把你的读取枚举出来。改一个主键意味着一次表迁移,而非一次 ALTER TABLE

下一步

复合键是项集合、一对多关系和大多数有用的索引设计之下的根基 —— 接下来读单表设计GSI 对比 LSI,看它们通向何处。

DynamoDB 表达式构建器里勾勒你的 KeyConditionExpression,然后试用 DynoTable,去浏览你真实的分区,看排序顺序对着你自己的表对齐起来。

更新于