進階閱讀時間 3 分鐘

DynamoDB 平行掃描

平行掃描把一個 Scan 拆成 N 個獨立的 Scan 請求,每個都認領 資料表的一個 Segment,這樣多個工作者就能同時讀它。當你想讀 整張資料表、讀得比單一分區吞吐量所允許的更快時,這是唯一的辦法。

什麼是 DynamoDB 平行掃描?

DynamoDB 平行掃描透過 SegmentTotalSegments 把一個 Scan 拆成 N 個獨立請求,每個請求認領資料表的一個 Segment,讓多個工作者同時並行讀取。這是讓整張資料表的讀取速度突破單一分區吞吐量限制的唯一方法——但它仍是完整讀取,你要為掃描到的每個項目付費。

  • 一次循序的 Scan 一次讀一個分區——它的速度被釘在 單一分區的吞吐量上,無論資料表多大都一樣。
  • Segment + TotalSegments 把讀取分片TotalSegments 個工作者上; 每個工作者平行地掃自己的那片。
  • DynamoDB 對分區鍵做雜湊來指派區段,所以各片可能會 失衡——工作者更多不一定就更快。
  • 它仍然是一個 Scan:你為讀取每個項目付費,而一個肥大的平行掃描 可能會把資料表的吞吐量從你的線上流量底下抽乾。

為什麼循序的 Scan 很慢

從 SQL 過來,整張資料表的讀取感覺像一個串流操作。在 DynamoDB 裡並非如此。資料表的資料分布在許多實體分區上,但 單一一個 Scan一次一個地走過它們,一頁 1 MB。

那意味著一個普通的 Scan 在某一刻只能從一個分區的吞吐量 預算裡拉取——即使資料表散布在數十個有閒置容量的分區上。 資料表越大,它爬得越久。 (AWS:平行掃描

用 Segment 和 TotalSegments 拆分讀取

平行掃描修掉這個瓶頸。你挑一個工作者數,把 TotalSegments 設成那個數,再給每個工作者一個從零開始、各不相同的 Segment。每個工作者發出自己的 Scan;DynamoDB 並行地服務它們。

Worker 0Scan  Segment=0  TotalSegments=4
Worker 1Scan  Segment=1  TotalSegments=4
Worker 2Scan  Segment=2  TotalSegments=4
Worker 3Scan  Segment=3  TotalSegments=4

每個工作者仍各自用 LastEvaluatedKey 分頁——它從第一頁到最後一頁 都擁有自己的區段。應用程式再把這四道流縫回一起。你現在一次 讀取的是四個分區份量的吞吐量,而不是一個。

一個實作範例:每晚匯出

假設你經營一張遙測資料表,sensor-readings。每個項目是一台 現場裝置的一筆讀數:

PK = "DEVICE#a83f"          (partition key — the device id)
SK = "TS#2026-06-22T03:14"  (sort key — ISO timestamp)
batteryMv  = 3120
tempC      = 41.8
firmwareTag = "fw-7.2.1"

每晚一個 cron job 把整張資料表傾印到 S3 給分析倉儲。 一次循序的 Scan 掃 80 GB 要花好幾個小時,卻幾乎用不到你預配的 讀取容量。所以你把它扇出到八個工作者:

Scan  sensor-readings  Segment=0  TotalSegments=8  ConsistentRead=falseScan  sensor-readings  Segment=7  TotalSegments=8  ConsistentRead=false

八個工作者、八個區段,一次資料表讀取大約快上八倍。如果你 只需要最近的讀數,加一個 FilterExpression 在列被送上線之前把舊的 時間戳丟掉——在運算式建構器裡建立並檢視 那個運算式:

FilterExpression:  begins_with(SK, :today)

DynamoDB 如何把項目指派到區段

這裡是讓人栽跟頭的部分。DynamoDB 把每個項目指派到區段的方式是 對它的分區鍵做雜湊——不是依列數、不是依位元組數。

所以每個共用同一個 PK 的項目都落在同一個區段。在 sensor-readings 裡,DEVICE#a83f 的所有讀數都去到一個工作者,無論那台裝置有多少 時間戳、或它的項目集合有多大。 (AWS:平行掃描

sensor-readings table對分區鍵做雜湊區段 0DEVICE#a83fDEVICE#1c20區段 1DEVICE#9be4區段 2(空的)

後果是:區段不均勻。一個工作者可能擁有三台有數百萬筆讀數的 多話裝置;另一個可能抽到空的那片。如果你的分區鍵擠成一團, 把 TotalSegments 開高也幫不上忙——你只是加了一些閒置工作者, 乾等那個熱的。鍵分布均勻,才是讓這個扇出划得來的東西。

在你跑它之前先看讀取成本

平行掃描是一個吞吐量事件,不是免費的午餐。誠實的問題是 「讀完這整張資料表會花多少讀取單位?」——而 DynoTable 會把一次掃描對著你 真實資料表所計量的讀取成本,逐區段顯示給你看, 這樣那個每晚的工作就不會在帳單上嚇到你。

陷阱與何時不必費這個事

  • 吞吐量懸崖。 一個高 TotalSegments 的掃描可能在幾秒內吃掉資料表的 全部讀取容量,餓死線上流量。在一張服務使用者的資料表上,用 Limit 參數節流每個工作者,或在離峰時段掃。 (AWS:平行掃描
  • 對一個存取模式它仍是錯的工具。 平行掃描是用於 刻意的整張資料表作業——匯出、回填、遷移。如果你伸手去拿 一個來回答一個會重複出現的查詢,那是一個建模訊號:加一個 GSI,把它改成一個 Query
  • PartiQL 裡的 SELECT * 是同一個掃描的偽裝。 它編譯成一個 循序的 Scan。當你真的需要跨項目的分析——一個 GROUP BY、 一個 JOIN、一個聚合——DynoTable 的 SQL Workbench 會在一組有界的 結果集上於用戶端跑那些,而不是猛捶資料表。
  • 強一致讓帳單翻倍。 一個 Scan 預設是最終 一致讀取。對一次匯出,除非你真的需要一個時間點的快照, 否則就讓 ConsistentRead=false

後續步驟

把你的鍵建模到日常讀取永遠不需要掃描——從 單一資料表設計Query 與 Scan開始。當一次整張資料表的作業真的是 正確的選擇,試用 DynoTable對著你自己的資料表跑一次 平行掃描,並即時看著讀取成本。

已更新