初級読了 4 分

DynamoDB の PartiQL vs SQL: 何が違うか(そして何が壊れるか)

DynamoDB の PartiQL における最大の混乱の原因は — 人間にとっても AI アシスタントにとっても — それをリレーショナル SQL として扱ってしまうことだ。だが PartiQL はそうではない。PartiQL は DynamoDB の既存オペレーションの上に乗った SQL 互換のサーフェス であって、結合・グループ化・集計ができるクエリエンジンではない。見慣れたキーワードの裏には、まったく異なる仕組みが隠れている。

メンタルモデル

すべての PartiQL ステートメントは、DynamoDB のネイティブオペレーションのいずれか 1 つにコンパイルされる:

書くものDynamoDB が実行するもの
SELECT … WHERE PK = …GetItem または Query
SELECT … (PK なし)Scan (テーブル全体を読む)
INSERT INTO …PutItem
UPDATE … WHERE PK=… AND SK=…UpdateItem (1 アイテム)
DELETE … WHERE PK=… AND SK=…DeleteItem (1 アイテム)

2 つのテーブルから読んだり、ハッシュ結合を組んだり、行を COUNT に畳み込んだりできるプランナは存在しない。あるオペレーションが単一の Get/Query/Scan/Put/Update/Delete にマップされなければ、PartiQL はそれを表現できない。これがすべてだ — 以下のすべては、この 1 つの事実の帰結にすぎない。

同じマッピングをフローとして見ると — WHERE 句が、SELECT を安価な Query にするか、テーブル全体の Scan にするかを決める:

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

各ステートメントはちょうど 1 つのネイティブオペレーションに解決される — その 1 対 1 のマッピングこそが、PartiQL が結合・グループ化・集計をできない理由だ。

何が違うか — 機能ごとに

DynoTable の SQL Workbench が 実行できる にはそれぞれ印が付けてある。Workbench はあなたのテーブルを DynamoDB の本物のクエリランタイムを通してマテリアライズし、その上で本物の SQL を実行する — DynamoDB のアクセスパターンの規則の中での SQL

機能標準 SQLDynamoDB の PartiQLDynoTable の Workbench
JOIN … ON … INNER / LEFT (PK または GSI パーティションキーへ)
RIGHT / FULL / CROSS / カンマ結合
自己結合 (まだ非対応)
サブクエリ / 派生テーブル
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 (attribute_not_exists / attribute_exists を使う)
PK なしの SELECT *スキャンする 暗黙のテーブル全体 Scan (コスト可視化付き)

何が壊れるか、そしてなぜ

これらは、クエリがワイヤに届く前に DynoTable の PartiQL バリデータが指摘する失敗であり — それぞれが本物の DynamoDB の制約に由来する。

  • パーティションキーのない SELECT * は隠れた Scan PartiQL はエラーにしない。ただ全アイテムを読み、その後でフィルタするだけだ。これは親しみやすい構文の裏に潜む、典型的な Query vs Scan のコストの落とし穴だ。
  • UPDATE / DELETE は完全なプライマリキーを必要とする。 これらは単一アイテムの UpdateItem/DeleteItem にマップされるので、WHERE がパーティションキー(そして複合キーテーブルならソートキーも)を確定させなければならない。「status = 'open' のすべての行を更新」を 1 ステートメントで行うことはできない。
  • 二重引用符は識別子であって文字列ではない。 DynamoDB の PartiQL はここで SQL 標準に従う: "name" は列名/テーブル名で、'name' は文字列値だ。値を二重引用符で囲むのは最もよくある初心者のミスで — バリデータのメッセージは文字どおり 「二重引用符は DynamoDB の PartiQL では識別子を区切るものであって文字列ではありません。文字列値には単一引用符を使ってください。」 となっている。
  • IN は丸括弧ではなく角括弧を使う: WHERE pk IN ['a','b']。PK 値 50 個 / 非キー値 100 個が上限。
  • JOIN なし、集計なし。 テーブルを結合したり行を畳み込んだりするエンジンが存在しない。これは シングルテーブル設計 のトレードオフだ: クエリ層が後からデータを再形成できないため、事前にアクセスパターンに合わせてモデリングする。

なぜ AI アシスタントはこれを間違えるのか

LLM はリレーショナル SQL の大海で訓練されているため、DynamoDB に対して JOINGROUP BYLIKE・インラインの LIMIT・二重引用符の文字列リテラルを自信たっぷりに吐き出す — そのどれもを DynamoDB は拒否する。DynoTable 独自のモデルクエリ自動修正が存在するのは、まさに安価なモデルがこうしたパターンを確実に生成するからだ: 二重エスケープされた引用符を取り除き、LIKE '%x%'containsIS NULLattribute_not_exists に書き換え、インラインの LIMIT をリクエストパラメータに引き上げる。あなたの AI が Postgres のように読める「PartiQL」を生成しているなら、それが見分けるサインだ。

各カードは、リレーショナル開発者が書こうとする SQL、それに対して DynamoDB PartiQL が実際に行うこと、そしてその理由を示します。「DynoTable で動作」と記されたカードは、Workbench が実行できる同等の 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 では実行できないクエリ

本当に JOINGROUP 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 / カンマ結合はなし。
  • 自己結合はまだなし、サブクエリなし、派生テーブルなし、ウィンドウ関数なし。
  • 結合と射影はスカラー属性に対して動作する。

生の API のために条件とキー式を組み立てるだけでよいなら、DynamoDB Expression Builder が PartiQL のサーフェスをまったく介さずに正しい FilterExpression / KeyConditionExpression を生成する。PartiQL を正しく行うには、実例付きの PartiQL の例 を参照。任意のクエリのコストを見積もるには、アイテムサイズ計算ツール を使う。なお PartiQL はワイヤフォーマットを変えることはなく — 値は依然として DynamoDB-JSON として送られる。クライアント選びに迷う? Workbench が 素の DynamoDB GUIDynobase に対してどう位置づけられるかを参照。

FAQ

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 タブを開いてください。

更新日