DynamoDB PartiQL vs SQL: 何が壊れるのか
DynamoDB の PartiQL をめぐる混乱の最大の原因は — 人間にとっても AI アシスタントにとっても — それをリレーショナルな SQL として扱ってしまうことです。PartiQL はそうではありません。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(1 アイテム) |
DELETE … WHERE PK=… AND SK=… | DeleteItem(1 アイテム) |
2 つのテーブルから読み込んだり、ハッシュ結合を構築したり、行を COUNT に畳み込んだりできるプランナは存在しません。ある操作が単一の Get/Query/Scan/Put/Update/Delete にマッピングされなければ、PartiQL はそれを表現できません。話はこれで全部です — 以下はすべて、この 1 つの事実の帰結にすぎません。
同じマッピングをフローとして見ると — WHERE 句が SELECT を安価な Query にするか、テーブル全体の Scan にするかを決めます。
各ステートメントは正確に 1 つのネイティブ操作に解決されます — この 1 対 1 のマッピングこそが、PartiQL が結合・グループ化・集計できない理由です。
何が違うのか — 機能ごとの比較
Workbench の列が PartiQL の No に対して Yes となっている箇所は、そのすべてが DynoTable の SQL が埋めるギャップです。Workbench はテーブルを DynamoDB の本物のクエリランタイムを通してマテリアライズし、その上で本物の SQL を実行します — DynamoDB のアクセスパターンのルール内で動く SQLです。
| 機能 | 標準 SQL | DynamoDB PartiQL | DynoTable Workbench |
|---|---|---|---|
JOIN … ON … | Yes | No | Yes — INNER / LEFT(PK または GSI パーティションキーへ) |
RIGHT / FULL / CROSS / カンマ結合 | Yes | No | No |
| 自己結合 | Yes | No | No(まだ未対応) |
| サブクエリ / 派生テーブル | Yes | No | No |
CTE(WITH …) | Yes | No | No |
UNION / INTERSECT / EXCEPT | Yes | No | No |
GROUP BY / HAVING | Yes | No | Yes |
集計(COUNT/SUM/AVG/MIN/MAX) | Yes | No | Yes |
DISTINCT | Yes | No | Yes |
CASE / CAST | Yes | No | Yes |
| ウィンドウ関数 | Yes | No | No |
ORDER BY | Yes、任意の列 | 部分的 — ソートキーのみ(パーティションキーの WHERE が必要) | Yes、任意の列 |
LIMIT | Yes | インラインでは不可(リクエストの limit パラメータを使う) | Yes |
LIKE | Yes | No(contains / begins_with を使う) | Yes |
IS NULL / IS NOT NULL | Yes | Yes(存在しない属性は NULL ではなく MISSING — IS MISSING を使う) | Yes |
PK なしの SELECT * | スキャン | 部分的 — 暗黙のテーブル全体 Scan | Yes(コストの可視化つき) |
何が壊れるのか、そしてなぜか
これらは、クエリがワイヤに届く前に DynoTable の PartiQL バリデータが検出する失敗です — それぞれが実際の DynamoDB の制約に起因します。
- なしの
SELECT *は隠れたScanです。 PartiQL はエラーを出さず、 すべてのアイテムを読み込んでから後でフィルタします。これは親しみやすい構文の裏に潜む、古典的な Query vs Scan のコストの落とし穴です。 UPDATE/DELETEには完全なプライマリキーが必要です。 これらは単一アイテムのUpdateItem/DeleteItemにマッピングされるため、WHEREはパーティションキー( テーブルではソートキーも)を確定させなければなりません。「status が 'open' のすべての行を更新する」 ことを 1 つのステートメントで行うことはできません。- 二重引用符は文字列ではなく識別子です。 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']。PK 値は最大 50 個、 非キー値は最大 100 個までです。JOINも集計もありません。 テーブルを結合したり行を畳み込んだりするエンジンは存在しません。 これは シングルテーブル設計 のトレードオフです。クエリ層が後から データを再構成できないため、アクセスパターンを前もってモデリングするのです。
なぜ AI アシスタントはこれを間違えるのか
LLM は膨大な量のリレーショナル SQL で訓練されているため、DynamoDB に対しても自信を持って JOIN、
GROUP BY、LIKE、インラインの LIMIT、二重引用符で囲んだ文字列リテラルを吐き出します — その
すべてを DynamoDB は拒否します。DynoTable 独自のモデルクエリ自動修正が存在するのは、まさに安価な
モデルがこれらのパターンを確実に生成するからです。二重エスケープされた引用符を取り除き、
LIKE '%x%' → contains、IS NULL → attribute_not_exists に書き換え、インラインの LIMIT を
リクエストパラメータへ引き上げます。あなたの AI が Postgres のように読める「PartiQL」を生成している
なら、それが見分けの印です。
DynoTable の SQL Workbench: PartiQL では実行できないクエリ
本当に JOIN や GROUP BY が必要になったとき、その答えが DynoTable の SQL Workbench です。
各 JOIN の結合先をパーティションキーに対して検証し、結合された行を 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 が PartiQL のサーフェスを
まったく使わずに正しい FilterExpression / KeyConditionExpression を生成します。PartiQL を正しく
使うには、実例つきの PartiQL の例 を参照してください。任意のクエリの
コストを見積もるには アイテムサイズ計算ツール を使いましょう。
PartiQL がワイヤフォーマットを変えることは決してなく、値は依然として
DynamoDB-JSON として送られる点に注意してください。クライアントを選んでいますか?
プレーンな DynamoDB GUI や Dynobase に対して
Workbench がどこに位置づけられるかを確認してください。
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 タブを開きましょう。