中階閱讀時間 3 分鐘

DynamoDB 索引投影:KEYS_ONLY、INCLUDE 與 ALL

當你建立一個次要索引時,DynamoDB 不會自動把整個 item 複製進去。 你要選擇哪些會被複製——也就是這個索引的投影。選太少,你的 查詢就得付出第二次讀取去取回其餘部分;全選,你則在每次更新時付出 額外的儲存與寫入成本。這是一個你在建立索引時設定一次、然後就得一直 承受的取捨。

(別把這個跟投影運算式(projection expression)搞混,後者是修剪 單次讀取所回傳的屬性。本頁談的是索引實際儲存了什麼——關於 另一個概念,請見投影運算式。)

什麼是 DynamoDB 索引投影?

投影就是 DynamoDB 從 base table 複製進次要索引的那組屬性。你要從三種類型中擇一:KEYS_ONLY(只有索引鍵)、INCLUDE(索引鍵加上一份指名的屬性清單),或 ALL(整個 item)。投影越多,需要回到 base table 取資料的次數越少,但儲存與寫入成本也越高。

  • 一個投影就是被複製進一個次要索引的那組屬性。
  • KEYS_ONLY — 只有資料表與索引的索引鍵。最小、最便宜。
  • INCLUDE — 索引鍵,加上一份你指定的額外屬性清單。
  • ALL — item 的每一個屬性。最大;查詢永遠不需要 base table。
  • 對 GSI 讀取一個未被投影的屬性,會強制從 base table 取回它——這是 一筆無聲的額外成本。(一個 LSI 可以 替你取回未投影的屬性,但要 付出額外的讀取成本。)
  • 投影越多 = 越多儲存 + 越多寫入成本,因為每一次 base-table 寫入 都會傳播到索引。

問題:那個害你讀兩次的索引

假設你經營一個客服中心,用一個 GSI 讓你能依優先順序列出未結工單。 你投影 KEYS_ONLY 以保持精簡。查詢回傳得很快——但它只給你工單 ID, 而你的佇列畫面需要每張工單的主旨、受指派人與存在時間。

於是現在你的程式碼要對 base table 做第二輪讀取,來把每一筆結果補齊。 你設計的那「一次查詢」其實是一次查詢外加 N 次 get,而你原本想省下 的延遲與成本又全回來了。對這個存取模式來說,那個投影太單薄了。

各種投影類型會複製什麼

Base item: keys + subject +assignee + age + bodyKEYS_ONLY: keys onlyINCLUDE: keys + subject,assignee, ageALL: every attribute
  • KEYS_ONLY 只儲存 base-table 鍵以及索引鍵。當查詢只需要 知道哪些 item 符合、而你會在別處取回細節(或根本不取)時,就用它。
  • INCLUDE 儲存索引鍵,加上一份你指名的固定屬性清單。最佳 平衡點:剛好投影你的查詢要繪製所需的欄位,不多不少。
  • ALL 複製整個 item。查詢完全從索引自給自足,代價是把整個 item 的儲存與寫入輸送量都複製進索引。

對這個客服佇列來說,用 INCLUDE 搭配 subjectassigneeage 才是對的選擇——佇列只靠索引就能繪製,不需要第二次讀取,也不必把 工單龐大的 body 複製進索引。

你正在權衡的成本

你投影的每一個屬性都會被 儲存第二份, 而且每當 base item 變動時就在索引裡被重寫一次。所以在一張頻繁 更新的表上採用大方的 ALL 投影,會讓儲存與寫入容量雙雙倍增。紀律 是:投影查詢會讀的東西,而不是「全部都來,以防萬一」。

一個值得知道的細節:在一個稀疏索引上,投影仍然只容納那些帶有 索引鍵的 item——所以在一個稀疏索引上 採用 INCLUDE/ALL 仍會維持很小,因為索引本身就很小。用 DynamoDB pricing calculator 衡量你投影 的儲存與寫入倍率,並用 DynamoDB expression builder 組裝索引 查詢本身。

在 DynoTable 中看見投影

DynoTable 會列出一張表的每一個次要索引,並讓你直接透過其中一個來 查詢。對 base table 與對一個 GSI 跑相同的存取模式,再比較結果——索引 結果中缺少的那些屬性,正是它沒有投影的那些,所以一個投影的效果不用 重讀資料表定義就看得見。

在 DynoTable 中選擇查詢要透過哪一個索引。
在 DynoTable 中選擇查詢要透過哪一個索引。

陷阱與下一步

  • GSI 上一個未投影的屬性,意味著一次 base-table 讀取 — 圍繞查詢 所繪製的內容來設計投影。
  • ALL 很少是免費的 — 它會讓儲存與寫入成本翻倍;除非索引真的 需要每一個欄位,否則預設用 INCLUDE
  • 投影大致上是固定的。 你之後無法不重建索引就自由編輯一個 GSI 的投影——一開始就要審慎選擇。
  • 相關: GSI vs LSI稀疏索引決定了一個投影實際上儲存多少。

想在重新設計之前,看看你每一個索引實際回傳什麼嗎? 下載 DynoTable,直接查詢你的表格。

已更新