入門閱讀時間 4 分鐘

DynamoDB 的 SQL 與 PartiQL 的侷限

DynamoDB 是一個 NoSQL 鍵值儲存,但它回答類 SQL 問題的能力比人們預想的要多——也遠比人們期望的要少。這是一份誠實的地圖:開箱即用你實際能得到多少 SQL-on-DynamoDB、它止步於何處,以及執行原生表層表達不了的 JOIN / GROUP BY / 聚合查詢的少數幾種辦法。

能用 SQL 查詢 DynamoDB 嗎?

部分能。DynamoDB 內建了 ,一種相容 SQL 的語言,可按鍵做 SELECT/INSERT/UPDATE/DELETE,所以 SELECT * FROM "Orders" WHERE OrderID = 100 是能用的。但它是 DynamoDB API 之上一個相容 SQL 的表層,而不是一個 SQL 引擎——AWS 只支援它的一個_子集_,所以 JOINGROUP BYCOUNT(*) 都在外面。要用這些,你需要在其之上疊加一個引擎。

AWS 把 PartiQL 描述為 "一種相容 SQL 的查詢語言,用於在 Amazon DynamoDB 中 select、insert、update 和 delete 資料", 但同樣直言不諱:"Amazon DynamoDB 支援 PartiQL 查詢語言的一個_子集_。"你一伸手去用 JOINGROUP BYCOUNT(*),就已經越出了 PartiQL 能做的範圍——完整的逐項功能對比參見 PartiQL 與 SQL

PartiQL:一個相容 SQL 的表層,而非一個 SQL 引擎

PartiQL 把類 SQL 的語句對映到 SDK 所暴露的那些資料平面操作之上。帶 相等條件的 SELECT 編譯成一次 Query;不帶的 SELECT 編譯成一次 Scan。根據 AWS SELECT 參考

如果 WHERE 子句中沒有提供帶分割區索引鍵的相等或 IN 條件,使用 SELECT 語句可能導致一次全表掃描。

所以支配 QueryScan 的那套訪問模式規則依舊成立——PartiQL 只是把它們藏在了熟悉的語法後面。它不增加查詢規劃器、不增加連線、不增加基於集合的聚合。每條語句都收斂為一個原生操作:

一條沒有分割區索引鍵等值條件的 SELECT 會編譯成一次全表 Scan。在 us-east-1 的按需模式下,這會為每一個被檢查的項按最終一致每 4 KB 計 0.5 個 RCU——一張 500 MB、行大小 2 KB 的表,在任何 WHERE 過濾收窄結果集之前,就已經約 125,000 個 RCU。到定價計算器裡給 PartiQL 形態的讀取估個價。

你寫的DynamoDB 執行的
SELECT … WHERE PK = …GetItemQuery
SELECT …(無 PK)Scan(讀取整張表
INSERT INTO …PutItem
UPDATE … WHERE PK=… AND SK=…UpdateItem(單個項)
DELETE … WHERE PK=… AND SK=…DeleteItem(單個項)

如果某個操作無法歸約為單個 Get/Query/Scan/Put/Update/Delete,PartiQL 就是表達不了它。下面的一切都是這一個事實的推論。

PartiQL 覆蓋了什麼

DynamoDB 的 PartiQL 支援四種 DML/查詢語句:

  • SELECT —— 讀取項(編譯成 QueryScan
  • INSERT —— 新增一個項(PutItem
  • UPDATE —— 修改一個項(UpdateItem
  • DELETE —— 刪除一個項(DeleteItem

它也支援 事務和批次操作。一次格式良好的讀取,會用相等或 IN 條件鎖定分割區索引鍵:

SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESC

ORDER BY 是允許的,但 AWS 參考把排序索引鍵限制為"雜湊鍵或排序索引鍵"——也就是分割區索引鍵或 ,而非任意列。這就是 PartiQL 的 SELECT 所能接受的上限。想要可複製貼上的語句,參見 PartiQL 示例

PartiQL 做不了什麼

這些是開發者最常從"SQL"中期待的東西,而 PartiQL 一個都不支援

  • 沒有 JOIN PartiQL SELECT 語法 是單個的 FROM @@P0@@[.@@P1@@]——一張表或一個索引,絕不是按鍵關聯的兩張表。這就是 單表設計 的取捨:你要提前圍繞訪問模式建模,因為查詢層事後無法重塑資料。
  • 沒有 GROUP BY 它不在語法裡;沒有子句可以對行分組。
  • 沒有聚合函式。 PartiQL 函式參考 在"聚合函式"下恰好只列了一個函式:SIZE,它返回單個項某個屬性的位元組大小。跨行沒有 COUNTSUMAVGMINMAX。AWS 說得很直白:"本列表未包含的任何 SQL 函式,DynamoDB 目前都不支援。"
  • 沒有 LIKE、沒有子查詢、沒有 UNION、沒有視窗函式。 模式匹配用 contains / begins_with;其餘的則根本沒有對應物。

所以"上個月按客戶統計的總營收"——在任何關係型資料庫裡都是一行 GROUP BY——在 PartiQL 裡是表達不出來的。你得把資料掃出來,在應用程式碼裡聚合。

要對 DynamoDB 資料獲得真正的 JOIN / GROUP BY / 聚合行為,唯一的辦法是用一個在其之上執行真正 SQL 引擎的工具。對於互動式、臨時性的查詢,有兩個選擇:Amazon Athena 的聯合聯結器,以及 DynoTable 的 SQL Workbench。(對於週期性分析,DynamoDB 到 Amazon Redshift 的 zero-ETL 整合也能執行 SQL 連線和聚合。)

如何藉助 Amazon Athena 用真正的 SQL 查詢 DynamoDB

AWS 自己對"對 DynamoDB 用真正的 SQL"的答案,是 Amazon Athena DynamoDB 聯結器, 它"讓 Amazon Athena 能與 DynamoDB 通訊,從而你可以用 SQL 查詢你的表"。因為 Athena 是一個完整的 SQL 引擎,這_確實_能給你 JOIN 和聚合——AWS 的操作指南標題就是 "使用 Athena 訪問、查詢並連線 Amazon DynamoDB 表"。

代價在於搭建和開銷:

  • 它是一個你部署進自己帳戶的基於 Lambda 的聯合聯結器(透過 Athena 主控台或 Serverless Application Repository),經由 AWS Glue 處理 schema,並把結果溢寫到一個 S3 儲存桶 (聯結器文件)。
  • 在底層,它仍然使用 DynamoDB 的 QueryScan API 操作。AWS 警告說"使用掃描的查詢可能消耗大量讀取容量單元(RCU)",所以一條針對大表的分析查詢會讀取——並計量——大量的項 (聯結器開銷)。用 項大小計算器 來估算一條掃描密集型查詢的開銷。
  • INSERT INTO 這樣的寫入操作,聯結器不支援。

Athena 是週期性分析和 BI 儀表盤的對路工具。對於日常"我就想連線兩張表、瞄一眼結果"的場景,它太重了——那正是下一節要補上的空缺。

DynoTable 的 SQL Workbench:在 DynamoDB 訪問模式規則之內的 SQL

DynoTable 的 SQL Workbench 從一個桌面用戶端對你實時的 DynamoDB 表執行真正的 SQL——JOINGROUP BYCOUNT/SUM/AVG——無需搭建 Lambda、Glue 或 S3。它透過 DynamoDB 真實的 Query/Scan 執行時物化這些行,然後在你的桌面上本地對它們執行單條 SELECT

-- Runs in the DynoTable Workbench (NOT in PartiQL):
SELECT c.country, COUNT(*) AS orders, SUM(o.total) AS revenue
FROM orders o
INNER JOIN customers c ON o.customerId = c.PK
GROUP BY c.country
ORDER BY revenue DESC

"在 DynamoDB 訪問模式規則之內"這部分很重要。Workbench 並不假裝 DynamoDB 是 Postgres——它在底層仍然透過 Query/Scan 讀取,所以你始終清楚每條查詢的開銷,而且它強制執行 DynamoDB 的訪問模型,而非把它藏起來:

  • 僅支援 INNER JOINLEFT JOIN——ON 的目標屬性必須是分割區索引鍵或 GSI 分割區索引鍵。不支援 RIGHT / FULL / CROSS / 逗號連線。
  • 暫不支援自連線、子查詢、派生表、視窗函式。
  • 連線與投影作用於標量屬性。

如果你只是需要為原始 API 拼裝條件和鍵運算式——而非一條完整的 SQL 語句——DynamoDB Expression Builder 會生成正確的 FilterExpression / KeyConditionExpression,完全不必碰 PartiQL 表層。

如果你的目標是一個用於探索、除錯和分析表的 DynamoDB SQL 用戶端,Workbench 就填補了這個空缺——而 DynoTable 的其餘部分是圍繞它的一個完整 DynamoDB GUI

試用 DynoTable,對你自己的表執行真正的 SQL。

常見問題

能在 DynamoDB 上執行 SQL 嗎? 你可以執行 PartiQL,一個相容 SQL 的子集(按鍵做 SELECT/INSERT/UPDATE/DELETE)。要用 JOIN、GROUP BY 和聚合,你需要在其之上疊加一個 SQL 引擎:Amazon Athena DynamoDB 聯結器,或 DynoTable 的 SQL Workbench——一種單條 SELECT 的方言,支援 INNER/LEFT JOIN,沒有 CTE、UNION 或子查詢。

DynamoDB PartiQL 支援 JOIN 嗎? 不支援。PartiQL 的 SELECT 語法只有單個 FROM 表或索引,沒有連線語法。連線需要在 DynamoDB 之上疊加一個引擎。

PartiQL 支援 GROUP BY 或像 COUNT、SUM 這樣的聚合嗎? 不支援。沒有 GROUP BY 子句,唯一的"聚合"函式是 SIZE(單個項某個屬性的位元組大小)。跨行的 COUNTSUMAVGMINMAX 都不支援。

DynamoDB 是 SQL 還是 NoSQL? NoSQL——一個鍵值與文件儲存。PartiQL 在其上加了一層相容 SQL 的查詢語言,但 DynamoDB 沒有關係引擎、連線或聚合。

PartiQL 適合臨時查詢嗎? 對於按鍵的查詢,適合。對於分析性的臨時查詢(計數、彙總、連線),不適合——PartiQL 表達不了它們,而不加約束的 SELECT 會悄無聲息地變成全表掃描。

有能處理 JOIN 和 GROUP BY 的 DynamoDB SQL 用戶端嗎? 有——DynoTable 的 SQL Workbench 能從桌面對實時的表執行 JOIN/GROUP BY/聚合,Amazon Athena 則透過一個你部署在自己 AWS 帳戶裡的聯合聯結器來做到。

已更新