iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0
Build on AWS

從一個網站的誕生,看懂 AWS 架構與自動化的全流程!系列 第 16

Day 16 資料庫效能優化:DynamoDB GSI/LSI 與 Query / Scan 應用

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250930/20172743R08usySuEm.png

一、前言

DynamoDB 雖然是 Serverless 架構中高效能、低延遲的 NoSQL 資料庫,但若僅依賴單一主鍵(Partition Key + Sort Key)存取資料,查詢彈性有限。

當應用程式需要不同查詢角度時,就需要用到 **本地二級索引(LSI)和全域二級索引(GSI)**來最佳化查詢效率,避免濫用 Scan 導致成本高昂與效能下降,簡單來說,這個架構的用意就是教導開發者:「**如何以正確且高效的方式,從 DynamoDB 中取出資料,而非只是將資料存入」,**此 Lab 是針對以下痛點做出改善:

(1) 直接使用 Scan 會遍歷整個資料表,效能低且成本高,不適合大規模系統。

  • 痛點: DynamoDB 的 Scan 操作會遍歷整個資料表,無論您只想要查詢幾筆資料。這對於大型資料表來說,不僅會導致極高的延遲,還會消耗大量的讀取容量單位(RCU),從而產生高昂的費用
  • 這個架構的用意: 透過建立 GSI 或 LSI,您可以將 Scan 操作轉換為 Query 操作。Query 只會查詢索引中的一小部分資料,這讓查詢速度快了數千倍,並且大大降低了成本

(2) DynamoDB 的設計雖強調 Partition Key,但實際應用中常需要不同查詢角度(例如依使用者 ID 查詢,也可能依 Email 查詢),實現多維度的查詢彈性。

  • 痛點: 許多應用程式需要從不同的角度來查詢數據。例如,一個會員系統可能需要根據 UserID 查詢,也可能需要根據 Email 查詢,甚至需要使用者狀態 查詢
  • 這個架構的用意:
    • GSI (Global Secondary Index):扮演「跨維度查詢」的角色。它讓您可以針對非主鍵的屬性(例如 Email)進行查詢,就像在一個新的資料表上查詢一樣。
    • LSI (Local Secondary Index):扮演「同維度內額外排序」的角色。它讓您可以在同一個主鍵下,用不同的屬性(例如狀態)來進行排序和過濾。

(3) 缺乏索引設計會導致應用程式需在 Lambda 端進行大量過濾,增加延遲與計算成本,故需要減輕 Lambda 的計算負擔。(同第一點)

  • 痛點: 如果沒有正確的索引,您可能需要在 Lambda 程式碼中執行 Scan,然後在程式碼中過濾出您需要的資料。這會消耗大量的 Lambda 運算資源,增加延遲,並讓 Lambda 函數的程式碼變得複雜。
  • 這個架構的用意: 透過在 DynamoDB 層就完成精準的查詢,Lambda 函數只需要接收並處理最終的資料,而不需要承擔額外的過濾和運算工作,這使得整個系統更輕量、更高效。

💡在 Serverless 架構中,DynamoDB GSI 與 LSI 可讓應用程式快速依不同條件存取資料,減少 Lambda 的負擔,並保持高可擴展性。

二、需要使用到的服務

(1) Amazon DynamoDB:主要存放會員與應用資料,支援高效能查詢。
(2) Global Secondary Index (GSI):允許使用不同 Partition Key + Sort Key 查詢資料。
(3) Local Secondary Index (LSI):在相同 Partition Key 下提供額外的 Sort Key 查詢維度。
(4) AWS Lambda(選用):可用於示範應用程式層查詢資料並回傳給前端。
(5) Amazon CloudWatch:監控 Query 與 Scan 的效能與 RCUs/ WCUs 消耗。

三、架構/概念圖

https://ithelp.ithome.com.tw/upload/images/20250930/20172743GLvNbtWmvj.png

四、技術重點

(1) 優先使用 Query,避免大量 Scan,降低成本與延遲。
(2) GSI 適合跨 Partition Key 查詢(例如 Email、OrderID),LSI 則適合同一使用者不同維度查詢(例如不同狀態)。
(3) 規劃索引時要平衡效能與儲存成本,每個索引都會增加寫入成本。
(4) 搭配 CloudWatch MetricsDynamoDB Auto Scaling,動態調整 RCU/WCU,避免過度 Provisioning。

LSI(本地二級索引)和 GSI(全域二級索引) 的建立方式是不同的:

  • LSI無法在表格建立後新增。如果您現有的表格沒有 LSI,則無法透過後續操作新增。
  • GSI可以在表格建立後新增,這正是它的優點之一。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743ImfK8y9g28.png

五、Lab流程

1️⃣ 前置作業

2️⃣ 主要配置

💡該Lab會重新創建一個新的DynamoDB,單純測試LSI及GSI,因為筆者沒有先見之明,之前在Day9就沒有讓Cognito user在註冊時勾選其他項目,做註冊,故無其他索引可以供篩選。

1. 建立 DynamoDB Table:

  1. 進入「DynamoDB」頁面。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743Eo6vxEuO2q.png

  2. 創建一個新的資料表。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743yV7rWZB85l.png

  3. 設定資料表分區索引鍵為「UserID」,排序索引鍵為「CreatedAt」。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743Ws2BhhK77Z.png
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743pOFYnd9cJk.png

  4. 創建完成畫面。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743d0a7gbhS5T.png

2. 建立 LSI

  1. 進到剛剛創建的「DynamoDB」資料表中。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743CmzJBYnvVu.png

  2. 新增索引。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743YUKLzWOOok.png

  3. 設定資料表分區索引鍵為「UserID」,排序索引鍵為「Status」。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743M8UDc8uONB.png
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743n7sao29pCA.png

3. 建立 GSI

💡要等到前一個「索引」建立完成才能再創建新的,不然會報錯!
https://ithelp.ithome.com.tw/upload/images/20250930/20172743OEhmEdopbK.png

  1. 再新增一個索引。
    https://ithelp.ithome.com.tw/upload/images/20250930/201727434tk1OnwNcw.png

  2. 設定資料表分區索引鍵為「Email」,排序索引鍵為「CreatedAt」。
    https://ithelp.ithome.com.tw/upload/images/20250930/201727431H532YcYmy.png
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743QA2WXt8GvK.png

3️⃣ 測試驗證

1. 插入測試資料

  1. 打開AWS CLI。
    https://ithelp.ithome.com.tw/upload/images/20250930/20172743oxXxOC0TMB.png

  2. 插入測試用資料。

    • 範例程式碼

      aws dynamodb put-item \
        --table-name Users \
        --item '{"UserID":{"S":"U1001"},"CreatedAt":{"N":"20250913"},"Email":{"S":"test@example.com"},"Status":{"S":"ACTIVE"}}'
      

    https://ithelp.ithome.com.tw/upload/images/20250930/20172743w2kaZbfq48.png

2. 使用 Query by LSI 查詢

  • 範例程式碼

    aws dynamodb query \
      --table-name Users \
      --index-name StatusIndex \
      --key-condition-expression "UserID = :uid AND #st = :st_val" \
      --expression-attribute-names '{"#st":"Status"}' \
      --expression-attribute-values '{":uid":{"S":"U1001"},":st_val":{"S":"ACTIVE"}}'
    

https://ithelp.ithome.com.tw/upload/images/20250930/20172743TX9Z47aetY.png

3. 使用 Query by LSI 查詢

  • 範例程式碼

    aws dynamodb query \
      --table-name Users \
      --index-name EmailIndex \
      --key-condition-expression "Email = :em" \
      --expression-attribute-values '{":em":{"S":"test@example.com"}}'
    

https://ithelp.ithome.com.tw/upload/images/20250930/20172743G9374xPgkd.png

4. 測試 Scan(低效率)

💡如果資料較多這個指令會需要全數掃描過資料庫裡的所有資料,故效率較低。觀察 Scan 的 RCUs 消耗與延遲,對比 Query 效率。

  • 範例程式碼

    aws dynamodb scan --table-name Users
    

https://ithelp.ithome.com.tw/upload/images/20250930/20172743HhUiyY3YxH.png

六、結語

本 Lab 示範如何透過 GSI / LSI 提升 DynamoDB 查詢效率,並比較 Query 與 Scan 的差異,關鍵學習點在於:

  1. Query 比 Scan 更有效率,應盡量使用索引來避免全表掃描。
  2. GSI 與 LSI 的應用場景不同,設計索引需依業務需求決定。
  3. 在 Serverless 架構下,正確的索引規劃能降低 Lambda 計算壓力並節省整體成本。

上一篇
Day 15 API 流量管制:API Gateway x Usage Plan 最佳化
系列文
從一個網站的誕生,看懂 AWS 架構與自動化的全流程!16
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言