DynamoDB 支持外键吗?

不支持。DynamoDB 没有外键、参照完整性约束,也没有级联删除——作为一个 NoSQL 数据库,它从不强制项与项之间或表与表之间的关系。关系要由你自己来建模:把相关数据反规范化进同一个项,或者用单表设计把相关的项放在同一个分区键之下。要看见并遍历这些建模出来的关系,DynoTable 的 Smart Table 会在画布上把两张表的关系画出来,并浏览连接后的行。

为什么没有外键

外键的存在是为了支撑跨规范化表的连接并强制完整性。DynamoDB 刻意省掉了 JOIN 运算符(AWS 建议改用反规范化),所以外键约束会去管一个查询模型根本不使用的关系。没有任何东西阻止你把另一个项的键作为属性 下来——DynamoDB 只是不会校验它,也不会级联。

那关系是怎么建模的

  • 嵌入——小而有界的子数据,作为列表或映射放在父项内部。
  • 同分区放置——父项和子项共用一个分区键、用不同的排序键,于是一次 Query 就能返回整个关系;这正是单表设计的核心。
  • 复制——把每个访问模式需要的字段复制到需要它们的项上,用写入时的维护换取单次请求的读取。

一对多多对多两篇指南分别深入讲了每种形态。

在真正要紧时强制完整性

对于那些你原本会依赖约束的场景,DynamoDB 给了你一些积木:条件表达式会基于被写入项的状态来守住这次写入,而事务里的 ConditionCheck 能在同一个全有或全无的操作中,校验_另一个_项(比如父项)是否存在。级联删除则变成显式的应用逻辑,或者一次由 Streams 驱动的清理。

真跑起来是什么样

我们在 pk = "CUSTOMER#1" 下面放了一个 PROFILE 项和两个 ORDER# 项,删掉了那个 profile,然后再查询这个分区:

Count: 2
[{"sk":{"S":"ORDER#1"},"pk":{"S":"CUSTOMER#1"}},
 {"sk":{"S":"ORDER#2"},"pk":{"S":"CUSTOMER#1"}}]

删除返回了成功。两个孤儿,没有警告,也没有可以捕获的错误。在 PostgreSQL 里,同样这次删除会失败、会级联,或者把子项的引用置空,取决于你声明的是哪种约束。

接着是最接近的替代品:一次在写第三个订单之前先对父项做条件检查的 TransactWriteItems

TransactionCanceledException: Transaction cancelled, please refer cancellation
reasons for specific reasons [ConditionalCheckFailed, None]

CancellationReasons: [
  {"Code":"ConditionalCheckFailed","Message":"The conditional request failed."},
  {"Code":"None"}
]

数组的位置对应你 TransactItems 的位置,所以 [ConditionalCheckFailed, None] 是说动作 0(父项检查)失败了,动作 1(子项写入)没问题。只有一个守卫时,这读起来一目了然;有八个动作时,那个数组就是你唯一能弄清是哪一个出问题的途径。

它也要计费。一次事务写入每个项消耗两个写单元,而 AWS 明确写了 "this capacity is consumed even when the transaction is canceled"。每一次被拒绝的写入,花的钱和被接受的一样多。

深入了解

单表设计开始,在表达式构建器里搭出那些守卫条件,然后下载 DynoTable 来可视化地浏览这些关系——它的 Smart Table 会在画布上把父表和子表连起来,让你在一个视图里看到整个项集合。

参考资料

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

孤儿子项查询和那段取消输出,是 2026-07-28 在 Node v24.18.0 上用 @aws-sdk/client-dynamodb 3.1095.0 针对 DynamoDB Local 3.3.0 复现的。

无需控制台即可使用 DynamoDB

一款快速的 DynamoDB 桌面客户端,可运行 DynamoDB 无法执行的真正 SQL——JOINs、GROUP BY、聚合——并支持可视化编辑和运行在你自己的 Bedrock 密钥上的 AI agent。

30 天免费试用,无需信用卡 — 之后为无时间限制的免费版。