入门阅读约 4 分钟

DynamoDB PartiQL 与 SQL:差异何在(以及哪些会失效)

DynamoDB PartiQL 最大的困惑来源——无论是对人还是对 AI 助手——都是把它当成关系型 SQL。它不是。PartiQL 是覆盖在 DynamoDB 现有操作之上的一层兼容 SQL 的接口,而不是一个能够联接、分组或聚合的查询引擎。那些熟悉的关键字背后藏着一台截然不同的机器。

心智模型

每一条 PartiQL 语句最终都会编译为 DynamoDB 的某个原生操作:

你写的内容DynamoDB 实际运行
SELECT … WHERE PK = …GetItemQuery
SELECT … (no PK)Scan(读取整张表
INSERT INTO …PutItem
UPDATE … WHERE PK=… AND SK=…UpdateItem(单个 item)
DELETE … WHERE PK=… AND SK=…DeleteItem(单个 item)

没有任何查询规划器能从两张表中读取、构建哈希联接,或把若干行折叠成一个 COUNT。如果某个操作无法映射到单个 Get/Query/Scan/Put/Update/Delete,PartiQL 就根本无法表达它。整个故事就这么简单——下面的一切都是这一个事实的推论。

同样的映射,以流程图呈现——WHERE 子句决定一个 SELECT 是一次廉价的 Query 还是一次全表 Scan

WHERE pins full PKno PK in WHEREPartiQL statementSELECT?Query (one partition)Scan (whole table)INSERT PutItemUPDATE UpdateItemDELETE DeleteItem

每条语句都恰好解析为一个原生操作——正是这种一对一的映射,让 PartiQL 无法联接、分组或聚合。

差异何在——逐项对比

下面标注了每一个 DynoTable 的 SQL Workbench 能够运行的 。Workbench 通过 DynamoDB 真实的查询运行时把你的表物化出来,然后在其上运行真正的 SQL——在 DynamoDB 访问模式规则之内的 SQL。

FeatureStandard SQLDynamoDB PartiQLDynoTable Workbench
JOIN … ON … INNER / LEFT(联接到 PK 或 GSI 分区键)
RIGHT / FULL / CROSS / comma-join
Self-join(暂不支持)
Subqueries / derived tables
CTEs (WITH …)
UNION / INTERSECT / EXCEPT
GROUP BY / HAVING
Aggregates (COUNT/SUM/AVG/MIN/MAX)
DISTINCT
CASE / CAST
Window functions
ORDER BY 任意列 仅排序键(需要分区键 WHERE 任意列
LIMIT 内联(改用请求的 limit 参数)
LIKE(改用 contains / begins_with
IS NULL / IS NOT NULL(改用 attribute_not_exists / attribute_exists
SELECT * without a PK扫描 静默的全表 Scan(带成本可见性)

哪些会失效,以及为什么

下面这些是 DynoTable 的 PartiQL 校验器在查询发出之前就会标记的失败——每一条都可以追溯到一个真实的 DynamoDB 约束。

  • 没有分区键的 SELECT * 是一次隐藏的 Scan PartiQL 不会报错;它只是读取每一个 item 再事后过滤,这正是友好语法背后那个经典的 Query 与 Scan 成本陷阱。
  • UPDATE / DELETE 需要完整的主键。 它们映射到单个 item 的 UpdateItem/DeleteItem,所以 WHERE 必须锁定分区键(在复合键表上还要锁定排序键)。你无法用一条语句“更新所有 status = 'open' 的行”。
  • 双引号是标识符,不是字符串。 DynamoDB PartiQL 在这一点上遵循 SQL 标准:"name" 是列名/表名,'name' 是字符串值。用双引号包裹一个值是最常见的新手错误——校验器的提示信息原文就是 “双引号在 DynamoDB PartiQL 中界定标识符,而不是字符串。字符串值请使用单引号。”
  • IN 用方括号,不用圆括号: WHERE pk IN ['a','b'],上限为 50 个 PK 值 / 100 个非键值。
  • 没有 JOIN,没有聚合。 没有引擎能合并表或折叠行。这就是单表设计的权衡:你要预先围绕访问模式建模,因为查询层无法在事后重塑数据。

为什么 AI 助手会搞错

LLM 是在海量的关系型 SQL 上训练出来的,所以它们会自信地针对 DynamoDB 生成 JOINGROUP BYLIKE、内联 LIMIT 以及双引号字符串字面量——而这些 DynamoDB 全都拒绝。DynoTable 自带的 model-query 自动修复正是为此而生,因为廉价模型会稳定地产出这些模式:它会剥离双重转义的引号,把 LIKE '%x%'containsIS NULLattribute_not_exists 重写,并把内联 LIMIT 提升为请求参数。如果你的 AI 生成的“PartiQL”读起来像 Postgres,那就是破绽。

每张卡片展示关系型开发者惯用的 SQL、DynamoDB PartiQL 对它的实际处理方式,以及背后的原因。标记为“可在 DynoTable 中运行”的卡片,会展示工作台能够运行的等效 SQL。
Joining two tables
PartiQL 不支持
SELECT o.id, c.name
FROM orders o
JOIN customers c ON o.customerId = c.PK
GROUP BY and aggregates
PartiQL 不支持
SELECT country, COUNT(*) AS orders, SUM(total) AS revenue
FROM orders
GROUP BY country
Subqueries
PartiQL 不支持
SELECT * FROM orders
WHERE customerId IN (SELECT PK FROM customers WHERE country = 'ES')
UNION across tables
PartiQL 不支持
SELECT PK FROM orders
UNION
SELECT PK FROM archived_orders
SELECT * (the hidden Scan)
可用,但有限制
SELECT * FROM orders
Updating many rows by a filter
PartiQL 不支持
UPDATE orders SET status = 'shipped'
WHERE status = 'open'
Quoting string values
可用,但有限制
SELECT * FROM users WHERE "name" = "Alice"

DynoTable 的 SQL Workbench:PartiQL 跑不了的查询

当你确实需要一个 JOIN 或一个 GROUP BY 时,DynoTable 的 SQL Workbench 就是答案。它会针对分区键校验每个 JOIN 的目标侧,通过 DynamoDB 真实的 Query/Scan 运行时把联接后的行物化出来,然后在其上运行你完整的 SQL(聚合、GROUP BYDISTINCTCASECAST)——在 DynamoDB 访问模式规则之内的 SQL。

-- 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

诚实的约束(Workbench 强制执行 DynamoDB 的访问模型,它并不假装自己是 Postgres):

  • 仅支持 INNER JOINLEFT JOIN——ON 的目标属性必须是分区键或 GSI 分区键。不支持 RIGHT / FULL / CROSS / comma-join。
  • 暂不支持自联接,不支持子查询,不支持派生表,不支持窗口函数。
  • 联接和投影作用于标量属性。

如果你只需要为原始 API 组合条件和键表达式,DynamoDB Expression Builder 会生成正确的 FilterExpression / KeyConditionExpression,完全不经过 PartiQL 这层接口。要把 PartiQL 用对,参见配套的 PartiQL 示例;要估算任意查询的成本,使用 item 大小计算器。请注意,PartiQL 从不改变线上格式——值仍然以 DynamoDB-JSON 的形式传输。在选客户端?看看 Workbench 与普通 DynamoDB GUIDynobase 相比表现如何。

常见问题

PartiQL 和 SQL 一样吗? 不一样。PartiQL 是一种兼容 SQL 的查询语言,但在 DynamoDB 上它只暴露那些能映射到单个 Get/Query/Scan/Put/Update/Delete 的操作。它没有联接、聚合、子查询或 GROUP BY

DynamoDB PartiQL 能做 JOIN 吗? 不能。DynamoDB PartiQL 无法联接表。DynoTable 的 SQL Workbench 可以通过 DynamoDB 真实的查询运行时物化数据,从而运行 INNER/LEFT JOIN(联接到分区键或 GSI 分区键)。

DynamoDB PartiQL 支持 GROUP BY 或 COUNT 吗? 不支持——DynamoDB PartiQL 中没有聚合,也没有 GROUP BYCOUNT/SUM/AVG/GROUP BY/HAVING 查询请使用 DynoTable 的 SQL Workbench。

为什么我的 SELECT * 成本这么高? 如果 WHERE 中没有分区键,PartiQL 会运行一次全表 Scan,并在过滤生效之前就对读取的每一个 item 计费。加上一个分区键谓词,就能把它变成一次 Query

在 PartiQL 中该用单引号还是双引号? 字符串值用单引号('CUSTOMER#42'),表名和属性名这类标识符用双引号("AppData")。用双引号包裹一个值是最常见的 PartiQL 错误。

准备好对 DynamoDB 运行真正的 SQL 了吗?下载 DynoTable 并打开一个 Workbench 标签页。

更新于