DynamoDB 并行扫描
一次并行扫描把一个 Scan 拆成 N 个独立的 Scan 请求,每个认领表的一个 Segment,这样
多个 worker 同时读它。这是把整张表读得比单个分区吞吐量允许的更快的唯一办法。
DynamoDB 并行扫描是什么?
DynamoDB 并行扫描通过 Segment 和 TotalSegments 把一个 Scan 拆成 N 个独立请求,每个认领表的一个 Segment,让多个 worker 并发读取。这是把整张表读得比单个分区吞吐量更快的唯一方式——但它仍是全表读取,你为每一个被扫描的条目付费。
- 一次顺序
Scan一次读一个分区——它的速度被钉在单个分区的吞吐量上,不管表有多大。 Segment+TotalSegments把读取分片 给TotalSegments个 worker;每个 worker 并行扫它自己的那一片。- DynamoDB 通过哈希 partition key 来分配 segment,所以分片可能不均衡——更多 worker 不一定意味着更快。
- 它仍然是一个
Scan:你为读取每一个 item 付钱,而一个臃肿的并行扫描会从你的在线 流量底下把表的吞吐量抽干。
为什么顺序 Scan 慢
从 SQL 过来,全表读取感觉像一次流式操作。在 DynamoDB 里它不是。表的数据散落在许多物理
分区上,但单个 Scan 一次一个 地走它们,每页 1 MB。
这意味着一个普通 Scan 在某一刻只能从一个分区的吞吐量预算里取——哪怕表铺在几十个分区上、
还有闲置容量。表越大,它爬得越久。
(AWS:并行扫描)
用 Segment 和 TotalSegments 拆分读取
一次并行扫描修掉这个瓶颈。你挑一个 worker 数量,把 TotalSegments 设成那个数,并给每个
worker 一个不同的、从零开始的 Segment。每个 worker 发出它自己的 Scan;DynamoDB 并发
地服务它们。
Worker 0 → Scan Segment=0 TotalSegments=4
Worker 1 → Scan Segment=1 TotalSegments=4
Worker 2 → Scan Segment=2 TotalSegments=4
Worker 3 → Scan Segment=3 TotalSegments=4
每个 worker 仍然独立地用 LastEvaluatedKey 分页——它从第一页到最后一页拥有自己的
segment。应用把这四条流再拼回去。你现在一次读到了四个分区的吞吐量,而不是一个。
一个实战例子:每夜导出
假设你跑一张遥测表,sensor-readings。每个 item 是一台现场设备的一次读数:
PK = "DEVICE#a83f" (partition key — 设备 id)
SK = "TS#2026-06-22T03:14" (sort key — ISO 时间戳)
batteryMv = 3120
tempC = 41.8
firmwareTag = "fw-7.2.1"每晚一个 cron 任务把整张表转储到 S3,给分析仓库用。一次对 80 GB 的顺序 Scan 要花几个
小时,却几乎用不到你预置的读取容量。所以你把它扇出到八个 worker:
Scan sensor-readings Segment=0 TotalSegments=8 ConsistentRead=false
…
Scan sensor-readings Segment=7 TotalSegments=8 ConsistentRead=false
八个 worker,八个 segment,一次表读取大约快了八倍。如果你只需要近期的读数,加一个
FilterExpression 在行上线之前丢掉旧时间戳——在
表达式构建器里构建并查看那个表达式:
FilterExpression: begins_with(SK, :today)DynamoDB 如何把 item 分配给 segment
这里是绊倒人的地方。DynamoDB 通过 哈希它的 partition key 把每个 item 分配给一个 segment——不是按行数,不是按字节数。
所以共享一个 PK 的每个 item 都落进同一个 segment。在 sensor-readings 里,DEVICE#a83f
的所有读数都去同一个 worker,不管那台设备有多少个时间戳、它的 item 集合有多大。
(AWS:并行扫描)
后果是:segment 不均匀。一个 worker 可能拥有三台话痨设备、上百万条读数;另一个可能抽到
一片空的。如果你的 partition key 扎堆,把 TotalSegments 调更高也帮不上忙——你只是加了些
闲着等热门那个的 worker。均匀的 key 分布才是让扇出物有所值的东西。
在运行之前看清读取成本
并行扫描是一桩吞吐量事件,不是免费午餐。诚实的问题是"读完整张表要花多少个读取单元?"—— 而 DynoTable 给你看一次扫描对你真实表的计量读取成本,逐 segment 地看,这样那个每夜任务就 不会在账单上给你惊吓。
坑,以及什么时候别费这劲
- 吞吐量悬崖。 一次高
TotalSegments的扫描可以在几秒内吃掉表的整个读取容量,把在线 流量饿死。在一张服务用户的表上,用Limit参数给每个 worker 限速,或在低峰扫描。 (AWS:并行扫描) - 对一个访问模式来说它仍然是错的工具。 并行扫描是给深思熟虑的全表任务用的——导出、 回填、迁移。如果你伸手去拿它来回答一个反复出现的 query,那是一个建模信号:加一个 GSI,把它变成一个 Query。
- PartiQL 里的
SELECT *是同一次扫描的伪装。 它编译成一个顺序Scan。当你真正需要 跨 item 的分析——一个GROUP BY、一个JOIN、一个聚合——DynoTable 的 SQL Workbench 在一个有界的结果集上于客户端跑这些,而不是猛锤那张表。 - 强一致让账单翻倍。 一个
Scan默认是最终一致读取。对导出来说,除非你真的需要一个 时间点快照,否则把ConsistentRead=false留着。
下一步
把你的 key 建模好,让日常读取永远不需要扫描——从 单表设计和 Query vs Scan开始。当一个全表任务确实是对的选择时, 试用 DynoTable,对你自己的表跑一次并行扫描,并实时看着读取成本。