使用 AWS CLI 的 DynamoDB Query

aws dynamodb query 會讀取一個分割區,並可選擇用排序索引鍵再收窄(Query 與 Scan 的比較說明何時該這麼做,鍵條件運算式則列出每一個合法的運算子)。CLI 額外疊上去的,是它自己的一層分頁邏輯,而這也是這個指令上大多數意外的來源。

程式碼

aws dynamodb query \
  --table-name 'Music' \
  --key-condition-expression '#hashKey = :hashKeyValue AND begins_with(#rangeKey, :rangeKeyValue)' \
  --expression-attribute-names '{"#hashKey":"Artist","#rangeKey":"SongTitle"}' \
  --expression-attribute-values '{":hashKeyValue":{"S":"Arturo Sandoval"},":rangeKeyValue":{"S":"C"}}'

#hashKey/#rangeKey 這兩個別名透過 --expression-attribute-names 解析成 Artist/SongTitle,這正是讓保留字不至於弄壞指令的關鍵。想要排序索引鍵由大到小排列,請加上 --no-scan-index-forward;預設是由小到大。

分頁

CLI 預設會自動分頁 — 它會在內部跟著 LastEvaluatedKey 走,並把合併後的結果印出來。若要手動分頁(例如結果集很大時),請用這些旗標控制:

aws dynamodb query \
  --table-name 'Music' \
  --key-condition-expression '#hashKey = :hashKeyValue' \
  --expression-attribute-names '{"#hashKey":"Artist"}' \
  --expression-attribute-values '{":hashKeyValue":{"S":"Arturo Sandoval"}}' \
  --page-size 100 \
  --max-items 50
# The output includes a "NextToken"; pass it back with --starting-token to continue.

說明

CLI 把分頁藏了起來,連成本數字也一起藏。先在一個分割區裡塞進 30 筆各約 60 KB 的項目,總共約 1.8 MB,因此會是兩個服務頁;接著用 --return-consumed-capacity TOTAL 以三種方式跑同一個查詢:

default (auto-paginate)  Count: 30   CapacityUnits: 132.0   LastEvaluatedKey: null
--no-paginate            Count: 18   CapacityUnits: 132.0   LastEvaluatedKey: {…S017}
--max-items 3            Count: 18   items printed: 3       NextToken: eyJFeGNsdXNpdmVTdGFydEtleSI6…

手動分頁才看得到真正的成本:第 1 頁是 18 筆、132.0 單位,第 2 頁是 12 筆、88.0 單位,所以這個查詢實際消耗了 220.0 個讀取單位。自動分頁的那一次執行發出了兩次呼叫、回傳全部 30 筆項目,卻只回報 132.0。CLI 會跨頁合併 ItemsCount,但不會合併 ConsumedCapacity,所以印出來的數字把這個查詢低估了 40%。如果你是靠 CLI 輸出來估算容量,請改用手動分頁,否則你只會照著一頁的量來估。

--max-items 是列印上限,不是 Limit。上面第三次執行印出三筆項目,卻仍然回報 Count: 18ScannedCount: 18,因為它截斷的那個服務頁就是 18 筆、大約 1 MB。你為整頁都付了錢。真正會限制讀取量的 DynamoDB 參數是 Limit,而 CLI 把它暴露成 --page-size

所以這兩個旗標做的是毫不相干的事--page-size 會變成 API 的 Limit,決定每次服務呼叫讀多少;--max-items 只決定合併後的結果有多少會送到你的終端機,並為剩下的部分發出一個 NextToken。那個 token 是 CLI 自己記帳用的一段 base64 資料,不是 DynamoDB 的 LastEvaluatedKey,而它是透過 --starting-token 傳回去的。

沒有 --limit,也沒有 --exclusive-start-key。在 2.36.9 上執行 aws dynamodb query help,語法摘要裡兩個都找不到:CLI 拿掉了 DynamoDB 那兩個分頁參數,換成它自己的三個。所以那個最自然的迴圈 — 從一次呼叫取出 LastEvaluatedKey 再餵給下一次 — 根本沒有旗標可以餵。回到原始 API 的路徑是 --cli-input-json,它會逐字接下整個請求:

--cli-input-json with "Limit": 5 and an "ExclusiveStartKey"
  → Count: 5   CapacityUnits: 37.0   LastEvaluatedKey: {"Artist":…,"SongTitle":"S007"}

請注意這同時也把分頁器關掉了:即使沒有加 --no-paginate,那次執行也只回傳一頁與一個真正的 LastEvaluatedKey。如果你要為一個很大的分割區寫一段 shell 迴圈,--cli-input-json 是誠實的做法,而 --no-paginate 是快的做法。

--query 是在錢花完之後才跑的。全域的 --query 旗標是套用在回應上的 JMESPath,執行在你的 shell 裡。像 Items[?Year > '2010'] 這樣的 JMESPath 運算式看起來像過濾條件,其實不是:在 JMESPath 看到之前,每一筆項目都已經被讀取、傳輸並計費。--filter-expression 至少能省下資料傳輸,但 AWS 明確寫著它「is applied after the items have already been read; the process of filtering does not consume any additional read capacity units」(擷取於 2026-07-28)。這句話是雙面刃,因為它同時也表示過濾條件不會讓讀取量變少。唯一能少讀的方法,是更收窄的鍵條件或一個索引。

不管你要求什麼,一頁就是 1 MB。「A single Query operation will read up to the maximum number of items set (if using the Limit parameter) or a maximum of 1 MB of data」(擷取於 2026-07-28)。比這更寬的分割區一定會分頁,這也是為什麼上面那個 30 筆的查詢從來不是一次呼叫。

查詢索引要多一個旗標--index-name 會把鍵條件切換到該索引的鍵上;而全域次要索引也會拒絕 --consistent-read。請見使用 AWS CLI 查詢 GSI

改用視覺化操作

要在一個指令裡同時把鍵條件、那兩張佔位符對應表與分頁迴圈都弄對,正是這裡真正的難處。免費的 DynamoDB Query Builder 會替你組出請求(含索引與分頁),並輸出成一段可直接執行的 CLI 指令。

想對你自己的資料表執行查詢 — 鍵條件表單、隨著捲動自動分頁的表格、把請求複製回一段 CLI 指令 — 請下載 DynoTable

相關指南

參考資料

已於 2026-07-28 以 aws-cli/2.36.9,對照連接埠 9000 上的 DynamoDB Local(amazon/dynamodb-local),在一個含 30 筆各約 60 KB 項目的分割區上實測。上方的筆數、token 與容量數據皆為擷取的實際輸出。DynamoDB Local 以文件所述的進位規則計算容量;請把絕對數字當成形狀的示範,在估算容量之前請對照線上服務量測你自己的資料表。

以視覺化方式建構此請求

在免費的 DynamoDB 查詢建構器中組合此操作 — 鍵條件、Filter、Index、Limit、排序方向與分頁迴圈 — 再把它複製成可執行的 SDK v3、CLI 或 boto3 程式。

開啟 DynamoDB 查詢建構器

不必透過主控台就能操作 DynamoDB

一款快速的 DynamoDB 桌面用戶端,可執行 DynamoDB 無法執行的真正 SQL — JOINs、GROUP BY、聚合 — 並支援視覺化編輯與使用你自己的 Bedrock 金鑰的 AI 代理。

30 天免費試用,無需信用卡 — 之後為無時間限制的免費方案。