入門閱讀時間 4 分鐘

SQL for DynamoDB:什麼有效、什麼無效,以及 Workbench

DynamoDB 是 NoSQL 鍵值儲存,但它回答 SQL 形狀問題的能力 比人們預期的多 — 也比人們所希望的少得多。這是一份誠實的對照:你 實際上能即開即用得到哪些 SQL-on-DynamoDB、它在哪裡止步,以及那幾種 能執行原生介面無法表達的 JOIN / GROUP BY / 彙總查詢的方法。

你能用 SQL 查詢 DynamoDB 嗎?簡短答案

部分可以。DynamoDB 內建 PartiQLAWS 文件 把它描述為「一個 SQL 相容的查詢語言,用於在 Amazon DynamoDB 中選取、插入、更新與 刪除資料。」所以你可以寫 SELECT * FROM "Orders" WHERE OrderID = 100,而它有效。

但 PartiQL 是 DynamoDB API 之上的一個 SQL 相容介面,不是一個 SQL 引擎。它說那套語法;它不會加上關聯式查詢能力。AWS 明確指出「Amazon DynamoDB 支援 PartiQL 查詢語言的一個子集」 (參考)。 你一伸手找 JOINGROUP BYCOUNT(*),就超出了 PartiQL 能做的範圍 — 完整的逐項功能比較請見 PartiQL vs SQL

PartiQL:一個 SQL 相容介面,不是 SQL 引擎

PartiQL 把 SQL 外觀的敘述對應到 SDK 所暴露的同一套資料平面操作。一個帶分割鍵相等性的 SELECT 編譯成一個 Query;一個 沒有的 SELECT 編譯成一個 Scan。依據 AWS SELECT 參考

若 WHERE 子句中未提供帶分割鍵的相等性或 IN 條件,使用 SELECT 敘述可能導致整表掃描。

所以治理 QueryScan 的同一套存取模式規則仍然適用 — PartiQL 只是把它們藏在熟悉的語法後面。它不加查詢規劃器、不加 join、也不加集合式彙總。每個敘述都折疊成一個原生 操作:

你寫的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 {{table}}[.{{index}}] — 一張資料表或一個索引,永遠不是兩張 依某個鍵關聯的資料表。這是 單表設計的取捨:你事先為 你的存取模式建模,因為查詢層無法在事後重塑 資料。
  • 沒有 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。

如何透過 Amazon Athena 用真正的 SQL 查詢 DynamoDB

AWS 自家對「DynamoDB 之上的真正 SQL」的答案是 Amazon Athena DynamoDB 連接器, 它「讓 Amazon Athena 能與 DynamoDB 通訊,使你能用 SQL 查詢 你的資料表。」因為 Athena 是一個完整的 SQL 引擎,這確實讓你能用 JOIN 與彙總 — AWS 的逐步教學就叫做 「使用 Athena 存取、查詢與 join Amazon DynamoDB 資料表。」

陷阱在於設定與成本:

  • 它是一個你部署到自己帳號中的 Lambda 型聯邦連接器 (透過 Athena 主控台或 Serverless Application Repository),透過 AWS Glue 取得 schema 並把結果溢寫到一個 S3 儲存桶 (連接器文件)。
  • 在底層它仍使用 DynamoDB 的 QueryScan API 操作。 AWS 警告「使用掃描的查詢可能消耗大量的讀取 容量單位(RCU)」,所以對大型資料表的分析查詢會讀取 — 並 計費 — 很多項目 (連接器成本)。 用 項目大小計算器來衡量一個 掃描繁重的查詢會花多少。
  • 透過連接器不支援 INSERT INTO 等寫入操作。

Athena 是排程分析與 BI 儀表板的對的工具。對日常的「我只是 需要 join 兩張資料表並用肉眼看結果」情況而言,它太重了 — 那正是下一節要填補的缺口。

DynoTable SQL Workbench:在 DynamoDB 存取模式規則之內的 SQL

DynoTable 的 SQL Workbench 從一個桌面用戶端對你的即時 DynamoDB 資料表 執行真正的 SQL — JOINGROUP BYCOUNT/SUM/AVG — 不需要架起 Lambda、Glue 或 S3。它透過 DynamoDB 真正的 Query/Scan 執行階段把資料列具現化,再在 上面的記憶體內引擎中執行你完整的 SQL:

-- 在 DynoTable Workbench 執行(而非 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 JOINON 的目標屬性必須是一個 分割鍵或 GSI 分割鍵。沒有 RIGHT / FULL / CROSS / 逗號 join。
  • 尚無自我 join、沒有子查詢、沒有衍生資料表、沒有視窗函式。
  • join 與投影作用於純量屬性。

如果你只需要為原始 API 組合條件與鍵運算式 — 而非一個完整的 SQL 敘述 — DynamoDB Expression Builder 能完全 不透過 PartiQL 介面就產生正確的 FilterExpression / KeyConditionExpression

如果你的目標是一個用來探索、除錯與分析資料表的 DynamoDB SQL 用戶端,Workbench 填補了那個缺口 — 而 DynoTable 的其餘部分是 圍繞它的一個完整 DynamoDB GUI

試用 DynoTable 對你自己的資料表跑真正的 SQL。

常見問題

你能在 DynamoDB 上跑 SQL 嗎? 你能跑 PartiQL,一個 SQL 相容的子集(按鍵的 SELECT/INSERT/UPDATE/DELETE)。要完整的 SQL — JOIN、GROUP BY、彙總 — 你需要在 它之上的一個 SQL 引擎:Amazon Athena DynamoDB 連接器,或 DynoTable 的 SQL Workbench。

DynamoDB PartiQL 支援 JOIN 嗎? 不支援。PartiQL 的 SELECT 語法只有一張 FROM 資料表或索引,沒有 join 文法。Join 需要一個架在 DynamoDB 之上的引擎。

PartiQL 支援 GROUP BY 或像 COUNT 與 SUM 的彙總嗎? 不支援。沒有 GROUP BY 子句,而唯一的「彙總」函式是 SIZE (單一項目的某個屬性的位元組大小)。跨資料列的 COUNTSUMAVGMINMAX 都不支援。

DynamoDB 是 SQL 還是 NoSQL? NoSQL — 一個鍵值與文件儲存。PartiQL 在其上加了一個 SQL 相容的查詢 語言,但 DynamoDB 沒有關聯式引擎、join 或彙總。

PartiQL 適合臨時查詢嗎? 對按鍵的查找,適合。對分析型的臨時查詢(計數、彙整、 join),不適合 — PartiQL 無法表達它們,而未受約束的 SELECT 會靜默地 變成整表掃描。

有沒有一個能處理 JOIN 與 GROUP BY 的 DynamoDB SQL 用戶端? 有 — DynoTable 的 SQL Workbench 從桌面對即時資料表執行 JOIN/GROUP BY/彙總,而 Amazon Athena 透過一個你 部署到 AWS 帳號中的聯邦連接器來做到。

已更新