DynamoDB PartiQL 与 SQL:什么会失效
DynamoDB PartiQL 最大的困惑来源——无论对人还是对 AI 助手——就是把它当成关系型 SQL。它不是。PartiQL 是 DynamoDB 现有操作之上的一个兼容 SQL 的表层,而不是一个能连接、分组或聚合的查询引擎。那些熟悉的关键字,掩盖了底层一台截然不同的机器。
DynamoDB PartiQL 与 SQL 有何不同?
PartiQL 借用了 SQL 的语法,却没有借用它的引擎。在 DynamoDB 上,每条语句都映射到单个原生操作——GetItem、Query、Scan、PutItem、UpdateItem 或 DeleteItem——所以没有 JOIN、GROUP BY、子查询或聚合。它读起来像 SQL,但只能做那些键值操作本就能做的事。
每条 PartiQL 语句都会向下编译成 DynamoDB 的某一个原生操作:
| 你写的 | DynamoDB 运行的 |
|---|---|
SELECT … WHERE PK = … | GetItem 或 Query |
SELECT …(无 PK) | Scan(读取整张表) |
INSERT INTO … | PutItem |
UPDATE … WHERE PK=… AND SK=… | UpdateItem(单个项) |
DELETE … WHERE PK=… AND SK=… | DeleteItem(单个项) |
没有哪个规划器能从两张表读取、构建哈希连接,或把多行折叠成一个 COUNT。如果某个操作无法映射到单个 Get/Query/Scan/Put/Update/Delete,PartiQL 就是表达不了它。这就是全部真相——下面的一切都是这一个事实的推论。
同样的映射,以流程呈现——WHERE 子句决定一个 SELECT 是一次廉价的 Query,还是一次全表 Scan:
每条语句都解析为恰好一个原生操作——正是这种一对一映射,让 PartiQL 无法连接、分组或聚合。
有何不同——逐项对比
只要 Workbench 那一列标着是、而 PartiQL 标着否,那就是 DynoTable 的 SQL 弥补的一处空缺。Workbench 通过 DynamoDB 真实的查询运行时把你的表物化出来,然后在其之上运行真正的 SQL——在 DynamoDB 访问模式规则之内的 SQL。
| 功能 | 标准 SQL | DynamoDB PartiQL | DynoTable Workbench |
|---|---|---|---|
JOIN … ON … | 是 | 否 | 是 —— INNER / LEFT(连到一个 PK 或 GSI 分区键) |
RIGHT / FULL / CROSS / 逗号连接 | 是 | 否 | 否 |
| 自连接(Self-join) | 是 | 否 | 否(暂不支持) |
| 子查询 / 派生表 | 是 | 否 | 否 |
CTE(WITH …) | 是 | 否 | 否 |
UNION / INTERSECT / EXCEPT | 是 | 否 | 否 |
GROUP BY / HAVING | 是 | 否 | 是 |
聚合(COUNT/SUM/AVG/MIN/MAX) | 是 | 否 | 是 |
DISTINCT | 是 | 否 | 是 |
CASE / CAST | 是 | 否 | 是 |
| 窗口函数 | 是 | 否 | 否 |
ORDER BY | 是,任意列 | 部分——仅排序键(需要分区键 WHERE) | 是,任意列 |
LIMIT | 是 | 无内联写法(用请求的 limit 参数) | 是 |
LIKE | 是 | 否(用 contains / begins_with) | 是 |
IS NULL / IS NOT NULL | 是 | 是(缺失的属性是 MISSING,而非 NULL——用 IS MISSING) | 是 |
没有 PK 的 SELECT * | 触发扫描 | 部分——悄无声息的全表 Scan | 是(带开销可见性) |
什么会失效,以及为什么
这些是 DynoTable 的 PartiQL 校验器在查询触网之前就会标出的失败——每一个都追溯到一条真实的 DynamoDB 约束。
- 没有 的
SELECT *是一次隐藏的Scan。 PartiQL 不会报错;它只是读取每一个项、之后再过滤,这正是那个藏在友好语法背后的经典 Query 与 Scan 开销之坑。 UPDATE/DELETE需要完整的主键。 它们映射到单项的UpdateItem/DeleteItem,所以WHERE必须锁定分区键(在 表上还要锁定排序键)。你无法在一条语句里"更新所有 status = 'open' 的行"。- 双引号是标识符,不是字符串。 DynamoDB PartiQL 在这里遵循 SQL 标准:
"name"是列名/表名,'name'是字符串值。用双引号引一个值是最常见的新手错误——校验器的提示原话就是 "Double quotes delimit identifiers in DynamoDB PartiQL, not strings. Use single quotes for string values." IN用方括号,不用圆括号:WHERE pk IN ['a','b'],上限为 50 个 PK 值 / 100 个非键值。- 没有
JOIN、没有聚合。 没有引擎去合并表或折叠行。这就是 单表设计 的取舍:你要提前围绕访问模式建模,因为查询层事后无法重塑数据。
为什么 AI 助手会搞错
LLM 是在浩如烟海的关系型 SQL 上训练出来的,所以它们会理直气壮地对 DynamoDB 抛出 JOIN、GROUP BY、LIKE、内联的 LIMIT,以及双引号字符串字面量——而这些 DynamoDB 全都拒绝。DynoTable 自己的模型查询自动修复功能存在的原因,恰恰就是廉价模型会稳定地产出这些模式:它会剥掉双重转义的引号,把 LIKE '%x%' 改写成 contains,把 IS NULL 改写成 attribute_not_exists,并把内联的 LIMIT 提升为请求参数。如果你的 AI 生成的"PartiQL"读起来像 Postgres,那就是破绽。
DynoTable 的 SQL Workbench:PartiQL 跑不了的查询
当你确实需要一个 JOIN 或一个 GROUP BY 时,答案是 DynoTable 的 SQL Workbench。它会对每个 JOIN 的连接侧(to-side)校验其是否为分区键,通过 DynamoDB 真实的 Query/Scan 运行时物化被连接的行,然后在其之上运行单条 SELECT(聚合、GROUP BY、DISTINCT、CASE、CAST)——在 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 JOIN和LEFT JOIN——ON的连接侧属性必须是分区键或 GSI 分区键。不支持RIGHT/FULL/CROSS/ 逗号连接。 - 暂不支持自连接、子查询、派生表、窗口函数。
- 连接与投影作用于标量属性。
如果你只是需要为原始 API 拼装条件和键表达式,DynamoDB Expression Builder 会生成正确的 FilterExpression / KeyConditionExpression,完全不必碰 PartiQL 表层。想把 PartiQL 用对,参见完整演示的 PartiQL 示例;想估算任意查询的开销,用 项大小计算器。注意,PartiQL 从不改变传输格式——值仍然以 DynamoDB-JSON 的形式传输。在挑客户端?看看 Workbench 相对一个 普通 DynamoDB GUI 或 Dynobase 的定位。
常见问题
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 BY。对于 COUNT/SUM/AVG/GROUP BY/HAVING 查询,请用 DynoTable 的 SQL Workbench。
为什么我的 SELECT * 开销这么大?
因为 WHERE 里没有分区键,PartiQL 会运行一次全表 Scan,并在过滤生效之前对读取的每个项计费。加一个分区键谓词,把它变成一次 Query。
在 PartiQL 里该用单引号还是双引号?
字符串值用单引号('CUSTOMER#42'),表名、属性名之类的标识符用双引号("AppData")。用双引号引一个值是最常见的 PartiQL 错误。
准备好对 DynamoDB 运行真正的 SQL 了吗?下载 DynoTable 并打开一个 Workbench 标签页。