DynamoDB 並行掃描
並行掃描把一次 Scan 拆成 N 個獨立的 Scan 請求,每個認領表的一個 Segment,從而讓多個工作程序同時讀取它。它是 Scan API 提供的、唯一一種讀取整張表能快過單個分割區吞吐量所允許速度的辦法。
什麼是 DynamoDB 並行掃描?
DynamoDB 並行掃描把一次 Scan 拆成 N 個獨立請求,每個透過 Segment 和 TotalSegments 認領表的一個 Segment,從而讓多個工作程序並行讀取它。它是 Scan API 提供的、唯一一種讀取整張表能快過單個分割區吞吐量所允許速度的辦法——但它仍然是一次完整讀取,所以你要為掃描到的每一個條目付費。
- 順序
Scan一次讀取一個分割區——它的速度被限制在單個分割區的吞吐量上,無論表有多大。 Segment+TotalSegments把讀取分片給TotalSegments個工作程序;每個工作程序並行掃描自己那一片。- DynamoDB 對做雜湊來分配段,所以各片可能一頭沉——工作程序更多並不總意味著更快。
- 它仍然是一次
Scan:你要為讀取每一個條目付費,而一次龐大的並行掃描會把表的吞吐量從你實時流量腳下抽乾。
為什麼順序 Scan 慢
從 SQL 過來,整表讀取感覺像是一次流式操作。在 DynamoDB 裡並非如此。表的資料分佈在許多物理分割區上,但單次 Scan 是一次一個地走過它們,每頁 1 MB。
這意味著一次普通的 Scan 在任一時刻只能從一個分割區的吞吐量預算裡拉取——即便這張表鋪在幾十個有空閒容量的分割區上。表越大,它爬得越久。(AWS:並行掃描)
用 Segment 和 TotalSegments 拆分讀取
並行掃描修復了這個瓶頸。你挑一個工作程序數量,把 TotalSegments 設成那個數,再給每個工作程序一個不同的、從零開始的 Segment。每個工作程序發出自己的 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
每個工作程序仍然用 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 作業把整張錶轉儲到 S3,供分析數倉使用。對 80 GB 做一次順序 Scan 要花好幾個小時,卻幾乎沒動用你預置的讀取容量。於是你把它鋪開到八個工作程序上:
Scan sensor-readings Segment=0 TotalSegments=8 ConsistentRead=false
…
Scan sensor-readings Segment=7 TotalSegments=8 ConsistentRead=false
八個工作程序,八個段,一次整表讀取大約快了八倍。如果你只需要最近的讀數,加一個 FilterExpression,在行到達線路之前先丟掉舊的時間戳——在運算式構建器裡構造並檢查那個運算式:
FilterExpression: begins_with(SK, :today)DynamoDB 如何把條目分配給段
這裡是讓人栽跟頭的部分。DynamoDB 透過對分割區索引鍵做雜湊把每個條目分配給某個段——不是按行數,也不是按位元組數。
所以共享同一個 PK 的每個條目都落在同一個段裡。在 sensor-readings 裡,DEVICE#a83f 的所有讀數都歸一個工作程序,無論那個裝置有多少個時間戳、或它的有多大。(AWS:並行掃描)
後果是:各段不均勻。一個工作程序可能擁有三臺話癆裝置、上百萬條讀數;另一個可能抽到一片空的。把 TotalSegments 調更高也幫不上忙,如果你的分割區索引鍵扎堆的話——你只是添了一些閒著的工作程序,乾等著那個熱的。均勻的鍵分佈才是讓這種扇出真正划算的東西。
執行之前先看清讀取成本
並行掃描是一次吞吐量事件,不是免費午餐。誠實的問題是"我正要讀取這整張表的多大一部分?"——在 DynoTable 執行整表讀取之前,它會用一個確認對話方塊攔住你,顯示錶的近似大小和條目數量以及一條讀取容量警告,然後在讀取進行時流式呈現實時的"已掃描條目數"進度,好讓那個夜間作業不會給你驚喜。
陷阱,以及何時別費這個勁
- 吞吐量懸崖。一次高
TotalSegments的掃描能在幾秒內吃光表的全部讀取容量,把實時流量餓死。在一張服務使用者的表上,用Limit引數給每個工作程序限速,或在非高峰時段掃描。(AWS:並行掃描) - 對某個訪問模式來說它仍然是錯的工具。並行掃描是用於刻意的整表作業的——匯出、回填、遷移。如果你伸手去用它來回答一個反覆出現的查詢,那是一個建模訊號:加一個 GSI,把它變成一次 Query。
- PartiQL 裡的
SELECT *是同一次掃描換了層皮。它會編譯成一次順序Scan。當你確實需要跨條目分析時——一個GROUP BY、一個JOIN、一次聚合——DynoTable 的 SQL Workbench 會在一個有界的結果集上於用戶端執行這些,而不是猛捶那張表。 - 強一致會讓賬單翻倍。
Scan預設使用的讀取。對於匯出,除非每一頁都必須反映最新的寫入,否則就讓ConsistentRead=false——並且要注意,即便一次強一致的掃描也橫跨幾分鐘,所以它不是一個時間點快照(要那個就用 PITR/Export)。
後續步驟
對鍵建模,好讓日常讀取永遠不需要掃描——從單表設計和 Query vs Scan 開始。當一次整表作業確實是正確的選擇時,試試 DynoTable,用一個預先的大小與成本警告和實時掃描進度來執行整表讀取。