如何查看、浏览和编辑 DynamoDB 数据
你对一张 DynamoDB 表做的每一次"查看"或"更改",都会映射到一小组 API 操作之一——GetItem、Query、Scan、PutItem、UpdateItem、DeleteItem。底层并没有一个关系型的表查看器:"浏览一张表"字面上就是一次 Scan,而"编辑一行"是一次针对 的 UpdateItem。知道每次点击映射到哪个操作,就是一次廉价读取与一次你本不打算运行的全表扫描之间的分水岭。
DynoTable 是一个恰好覆盖这些操作的图形界面——它会在触网之前告诉你你即将运行哪一个,以及开销是多少。
如何浏览一张 DynamoDB 表
打开一张表去"看看里面有什么"是一次 Scan——它读取表或索引中的每一个项(AWS:"Amazon DynamoDB 中的 Scan 操作会读取表或二级索引中的每一个项。")。对小表没问题;对大表它就是 Query 与 Scan 中讲到的经典开销之坑。
单次 Scan 最多返回 1 MB 数据,然后交给你一个 LastEvaluatedKey 去取下一页——所以"浏览整张表"其实是一个分页循环(AWS:"单个 Scan 请求最多可检索 1 MB 数据"以及"Scan 响应中的 LastEvaluatedKey 应作为下一次 Scan 请求的 ExclusiveStartKey")。关于游标如何工作、以及为什么这里不存在偏移量式的页码,参见 分页。
如何筛选 / 扫描 DynamoDB 数据
陷阱在于:一个 并不能替你省掉一次扫描。DynamoDB 是在读取完成_之后_才应用筛选,所以你为扫描到的每一个项付费——而不只是你留下的那些行。
筛选表达式在
Scan完成之后、结果返回之前应用。因此,无论是否存在筛选表达式,一次Scan消耗的读取容量都相同。 —— AWS Scan 文档
响应把这一点摆到了明面上:ScannedCount 是"在应用任何 ScanFilter 之前评估的项数",而 Count 是筛选后幸存下来的(AWS)。一个很高的 ScannedCount 配上一个很小的 Count,正是低效扫描的特征。
如何查询一张 DynamoDB 表
一次 Query 是那种廉价、精准的读取——但它需要一个分区键。根据
AWS:
"你必须提供分区键属性的名称,以及该属性的单个值。Query 会返回具有该分区键值的所有项。你还可以选择提供一个排序键属性,并使用比较运算符来收窄搜索结果。"
所以一次 Query 只读取一个分区键下的项,可选地再用一个排序键条件收窄——绝不读取整张表。没有分区键,就没有 Query:你又退回到了 Scan。这个选择是 DynamoDB 中最重要的单个开销决策;完整拆解在 Query 与 Scan。
在 us-east-1 的按需模式下,打开一张表去「浏览」它,跑的是分页 Scan,对每一个被检查到的项按每 4 KB 0.5 RCU(最终一致读)计费 —— 如果你把一张由 1 KB 行组成的 10 GB 表全部加载出来,在 GUI 里这么滚一遍大约是 250 万 RCU 这个量级。而一次针对某个分区键的 Query 只读取那一个项集合。在定价计算器里估一估浏览和查询的差别。
要拼装 KeyConditionExpression / FilterExpression 而不必手写占位符语法,用 DynamoDB Expression Builder——它会输出 API 所期望的确切名称/值映射。
如何编辑 DynamoDB 中的一个项
编辑一个项是一次针对其完整主键的 UpdateItem。你不用重写整个项——你提供一个__,只指名你正在更改的那些属性:
UpdateItem
Key: { "PK": "USER#42", "SK": "PROFILE" }
UpdateExpression: SET email = :e, updatedAt = :t有两个常常绊倒人的事实,都出自 AWS 项文档:
- 你必须指定完整的主键,而不是它的一部分。 在一张 表上,那就是分区键_和_排序键。你无法按一个任意属性"编辑一行"——那需要先扫描才能找到键。
UpdateItem是一次 upsert。 "如果指定键的项不存在,UpdateItem会创建一个新项。否则,它会修改现有项的属性。"键里的一个笔误会悄无声息地创建一个新项,而不是报错。
如何删除一个项
一次 DeleteItem,同样以完整主键为键:"DeleteItem 删除具有指定键的项"(AWS)。与编辑同样的规则——你需要完整的键,所以删除"所有 status = 'open' 的行"不是一次调用;你要扫描/查询找到键,然后逐个删除。BatchWriteItem 把最多 25 个 put/delete 请求打成一捆(AWS:"BatchWriteItem 操作最多可包含 25 个独立的 PutItem 和 DeleteItem 请求"),但每一个仍然只针对一个键——没有 DELETE … WHERE。
如何查看嵌套 / JSON 数据
DynamoDB 项以一种带类型标签的传输格式(DynamoDB-JSON)存储,其中每个值都带一个一或两字母的类型描述符(S、N、M、L、SS… ——完整的描述符清单在
AWS 数据类型文档)。纯 JSON 没有 set 类型,所以一个数组会往返成一个列表(L),绝不会是一个字符串 set(SS)——这是一个真实的转换限制,而不是显示上的 bug。完整的类型映射在 DynamoDB 数据类型;要把一段 DynamoDB-JSON 数据转换成纯 JSON 再转回来,用 DynamoDB JSON 转换器。
超越浏览与编辑:DynamoDB 做不到的查询
Scan/Query/UpdateItem 覆盖了查看和编辑,但它们无法_分析_——DynamoDB 没有 JOIN、GROUP BY,也没有像 COUNT/SUM 这样的聚合函数,PartiQL 也不添加它们:它的 SELECT 语法就只是 SELECT … FROM table [WHERE …] [ORDER BY …],没有连接或分组子句(AWS PartiQL SELECT 参考),所以每条语句都映射到单个 Get/Query/Scan/Put/Update/Delete。DynoTable 的 SQL Workbench 通过 DynamoDB 真实的查询运行时物化你的表、并在其之上运行 SQL,填补了这个空缺——在 DynamoDB 访问模式规则之内的 SQL——但对于日常的浏览与编辑,上面那些操作就是全部的工具箱。
常见问题
如何在不用 AWS 控制台的情况下查看 DynamoDB 数据?
用一个发出同样 Scan/Query 调用的桌面图形界面。AWS 控制台通过分页扫描浏览表;像 DynoTable 这样的专用客户端做同样的事,但会显示消耗容量和你正在运行的操作。
如何编辑一个 DynamoDB 项?
对该项的完整主键发出一次 UpdateItem,用一个 SET 更新表达式只指名你正在更改的属性。在图形界面里,内联编辑单元格——它会替你编译成那次 UpdateItem。
为什么筛选仍然花掉一次全表扫描的开销? 因为 DynamoDB 是在扫描读取项之后才应用筛选。被筛掉的项仍然被读取并计量。要削减开销,按分区键(或一个 GSI)查询,而不是扫描。
能一次更新很多项吗?
没有 UPDATE … WHERE——每个 UpdateItem/DeleteItem 只针对单个主键。要在一次原子请求中更改多个项,TransactWriteItems 可应用最多 100 个写入动作(包括 Update),它们要么全部成功,要么全部回滚。否则你就扫描/查询收集键,然后逐个写入(每个 BatchWriteItem 最多 25 个)。
能用同样的方式浏览一张 DynamoDB Local 表吗? 能——把同一个图形界面指向本地终端节点。参见 DynamoDB Local。
想浏览、筛选并内联编辑 DynamoDB 表——还想运行 PartiQL 跑不了的 SQL 吗?下载 DynoTable。