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 会在画布上把父表和子表连起来,让你在一个视图里看到整个项集合。
参考资料
- What is Amazon DynamoDB? — Amazon DynamoDB Developer Guide
- Amazon DynamoDB Transactions: How it works — Amazon DynamoDB Developer Guide
- Best practices for NoSQL design — Amazon DynamoDB Developer Guide
- DynamoDB read and write operations — Amazon DynamoDB Developer Guide
最后核实于 2026-07-13,依据上方链接的 AWS 官方文档。
孤儿子项查询和那段取消输出,是 2026-07-28 在 Node v24.18.0 上用 @aws-sdk/client-dynamodb 3.1095.0 针对 DynamoDB Local 3.3.0 复现的。