DynamoDB のための SQL と PartiQL の限界
DynamoDB は NoSQL のキーバリューストアですが、人が思う以上に SQL 形式の問いに答えます — そして
期待するほどには答えません。これは正直な地図です。DynamoDB 上の SQL で実際に標準で得られるものは
何か、どこで止まるのか、そしてネイティブのサーフェスでは表現できない JOIN / GROUP BY / 集計の
クエリを実行するわずかな方法です。
DynamoDB を SQL でクエリできるのか?
部分的には。DynamoDB は を備えています。これはキーによる
SELECT/INSERT/UPDATE/DELETE のための SQL 互換言語で、SELECT * FROM "Orders" WHERE OrderID = 100 は動作します。ただしそれは DynamoDB API の上に載る SQL 互換のサーフェスであって、
SQL エンジンではありません — AWS は サブセット しかサポートしないため、JOIN、GROUP BY、
COUNT(*) は対象外です。それらには、上に載せたエンジンが必要になります。
AWS は PartiQL を
「Amazon DynamoDB のデータを選択、挿入、更新、削除するための SQL 互換のクエリ言語」
と説明していますが、「Amazon DynamoDB は PartiQL クエリ言語の サブセット をサポートする」とも
同じくらい明確に述べています。JOIN、GROUP BY、COUNT(*) に手を伸ばした瞬間、あなたは PartiQL に
できることの外にいます — 機能ごとの完全な比較は PartiQL vs SQL を参照して
ください。
PartiQL: SQL 互換のサーフェスであって、SQL エンジンではない
PartiQL は SQL 風のステートメントを、SDK が公開するのと同じデータプレーン操作にマッピングします。
の等価条件を持つ SELECT は Query に、それを持たない SELECT は
Scan にコンパイルされます。
AWS の SELECT リファレンス
によると:
WHERE 句でパーティションキーによる等価条件または IN 条件が指定されていない場合、
SELECTステートメントを使用するとテーブル全体のスキャンが発生する可能性があります。
つまり、Query と Scan を支配するのと同じアクセスパターンのルールが依然として適用されます —
PartiQL はそれらをおなじみの構文の裏に隠しているだけです。クエリプランナも、結合も、集合ベースの
集計も加えません。すべてのステートメントは 1 つのネイティブ操作に畳み込まれます。
パーティションキーの等価条件を持たない SELECT は、テーブル全体の Scan にコンパイルされます。
us-east-1 のオンデマンドでは、評価したアイテムごとに結果整合性で 4 KB あたり 0.5 RCU が
課金されます — 2 KB の行が入った 500 MB のテーブルなら、WHERE フィルターが結果を絞る
前におよそ 125,000 RCU です。PartiQL 形式の読み取りの単価は
料金計算ツールで確かめましょう。
| 記述するもの | 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 アイテム) |
ある操作が単一の Get/Query/Scan/Put/Update/Delete に還元されなければ、PartiQL はそれを表現できません。 以下はすべて、その 1 つの事実の帰結です。
PartiQL がカバーするもの
DynamoDB の PartiQL は 4 つの DML/クエリステートメントをサポートします。
- SELECT — アイテムを読む(
QueryまたはScanにコンパイル) - INSERT — アイテムを追加する(
PutItem) - UPDATE — アイテムを変更する(
UpdateItem) - DELETE — アイテムを削除する(
DeleteItem)
また、トランザクションとバッチ操作
もサポートします。整った読み取りは、等価条件または IN でパーティションキーをターゲットにします。
SELECT OrderID, Total
FROM "Orders"
WHERE OrderID IN [1, 2, 3] ORDER BY OrderID DESCORDER BY は許可されていますが、AWS のリファレンスは並べ替えのキーを「ハッシュキーまたはソートキー」
— パーティションキーまたはであって任意の列ではない — に制限しています。これが
PartiQL の SELECT が受け付けるものの上限です。コピー&ペーストで使えるステートメントは
PartiQL の例 を参照してください。
PartiQL ができないこと
これらは開発者が「SQL」に最もよく期待するもので、PartiQL はそのどれもサポートしません。
JOINはありません。 PartiQL のSELECT構文 は単一のFROM {{table}}[.{{index}}]です — 1 つのテーブルまたは 1 つのインデックスであって、キーで 関連づけられた 2 つのテーブルではありません。これは シングルテーブル設計 のトレードオフです。クエリ層が後からデータを再構成できないため、アクセスパターンを前もって モデリングするのです。GROUP BYはありません。 文法にありません。行をグループ化する句が存在しません。- 集計関数はありません。
PartiQL の関数リファレンス
は「集計関数」の下にちょうど 1 つの関数
SIZEを挙げています。これは単一のアイテムについて 属性のサイズをバイト単位で返します。行をまたぐCOUNT、SUM、AVG、MIN、MAXはありません。 AWS ははっきりこう述べています。「このリストに含まれていない SQL 関数は、DynamoDB では現在 サポートされていません。」 LIKE、サブクエリ、UNION、ウィンドウ関数はありません。 パターンマッチングはcontains/begins_withを使い、残りにはまったく同等物がありません。
そのため、「先月の顧客別の総売上」— どんなリレーショナルデータベースでも 1 行の GROUP BY — は
PartiQL では表現できません。データをスキャンで取り出し、アプリケーションコードで集計することに
なるでしょう。
DynamoDB のデータに対して本物の JOIN / GROUP BY / 集計の挙動を得る唯一の方法は、その上で
実際の SQL エンジンを動かすツールです。インタラクティブなアドホッククエリには 2 つあります。
Amazon Athena のフェデレーテッドコネクタと、DynoTable の SQL Workbench です。(スケジュールされた
分析には、DynamoDB の Amazon Redshift へのゼロ ETL 統合も SQL の結合と集計を実行します。)
Amazon Athena で DynamoDB を本物の SQL でクエリする方法
「DynamoDB 上の本物の SQL」に対する AWS 自身の答えは、
Amazon Athena DynamoDB コネクタ
です。これは「Amazon Athena が DynamoDB と通信できるようにし、テーブルを SQL でクエリできるように
する」ものです。Athena は完全な SQL エンジンなので、これは JOIN と集計を 実際に 提供します —
AWS のウォークスルーは
「Athena を使用して Amazon DynamoDB テーブルにアクセス、クエリ、結合する」
と題されています。
難点はセットアップとコストです。
- これはアカウントにデプロイする Lambda ベースのフェデレーテッドコネクタです(Athena コンソール または Serverless Application Repository 経由)。スキーマのために AWS Glue を通して配線され、結果を S3 バケットにスピルします (コネクタのドキュメント)。
- 内部では依然として DynamoDB の
QueryとScanAPI 操作を使います。AWS は「スキャンを使用する クエリは大量の読み取りキャパシティユニット(RCU)を消費する可能性がある」と警告しているため、 大きなテーブルに対する分析クエリは多くのアイテムを読み取り — そして計上します (コネクタのコスト)。 スキャンの多いクエリのコストを測るには アイテムサイズ計算ツール を使ってください。 INSERT INTOのような書き込み操作はコネクタ経由ではサポートされません。
Athena は、スケジュールされた分析や BI ダッシュボードには適切なツールです。「ただ 2 つのテーブルを 結合して結果をざっと見たい」という日常のケースには重すぎます — それが次のセクションが埋めるギャップ です。
DynoTable の SQL Workbench: DynamoDB のアクセスパターンのルール内で動く SQL
DynoTable の SQL Workbench は、Lambda も Glue も S3 も立ち上げることなく、デスクトップクライアント
から、稼働中の DynamoDB テーブルに対して本物の SQL — JOIN、GROUP BY、COUNT/SUM/AVG — を
実行します。行を DynamoDB の本物の Query/Scan ランタイムを通してマテリアライズし、その上で
単一の SELECT を、デスクトップ上でローカルに実行します。
-- 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「DynamoDB のアクセスパターンのルール内で」という部分が重要です。Workbench は DynamoDB を Postgres の
ふりをさせません — 依然として内部で Query/Scan を通して読み取るため、各クエリのコストを意識でき、
DynamoDB のアクセスモデルを隠すのではなく強制します。
INNER JOINとLEFT JOINのみ —ONの対象属性はパーティションキーまたは GSI パーティション キーでなければなりません。RIGHT/FULL/CROSS/ カンマ結合はありません。- 自己結合はまだ、サブクエリ、派生テーブル、ウィンドウ関数もありません。
- 結合と射影はスカラー属性に対して動作します。
完全な SQL ステートメントではなく、生の API 向けの条件式とキー式を組み立てるだけでよいなら、
DynamoDB Expression Builder が PartiQL のサーフェスをまったく
使わずに正しい FilterExpression / KeyConditionExpression を生成します。
テーブルを探索、デバッグ、分析するための DynamoDB SQL クライアントが目的なら、Workbench が そのギャップを埋めます — そして DynoTable の残りの部分は、その周りを取り囲む完全な DynamoDB GUI です。
DynoTable を試して、自分のテーブルに対して本物の SQL を実行しましょう。
よくある質問
DynamoDB で SQL を実行できますか?
PartiQL は実行できます。これは SQL 互換のサブセット(キーによる SELECT/INSERT/UPDATE/DELETE)です。
JOIN、GROUP BY、集計には、上に載せた SQL エンジンが必要です。Amazon Athena DynamoDB
コネクタ、または DynoTable の SQL Workbench — INNER JOIN/LEFT JOIN を備えた単一 SELECT の
方言で、CTE、UNION、サブクエリはありません。
DynamoDB の PartiQL は JOIN をサポートしますか?
いいえ。PartiQL の SELECT 構文は単一の FROM テーブルまたはインデックスを持ち、結合の文法は
ありません。結合には、DynamoDB の上に載せたエンジンが必要です。
PartiQL は GROUP BY や COUNT、SUM のような集計をサポートしますか?
いいえ。GROUP BY 句はなく、唯一の「集計」関数は SIZE(1 アイテムの属性のバイトサイズ)です。
行をまたぐ COUNT、SUM、AVG、MIN、MAX はサポートされません。
DynamoDB は SQL ですか、NoSQL ですか? NoSQL — キーバリュー・ドキュメントストアです。PartiQL はその上に SQL 互換のクエリ言語を加えますが、 DynamoDB にはリレーショナルエンジンも、結合も、集計もありません。
PartiQL はアドホッククエリに向いていますか?
キーベースのルックアップにははい。分析的なアドホッククエリ(カウント、ロールアップ、結合)には
いいえ — PartiQL はそれらを表現できず、制約のない SELECT は暗黙のうちにテーブル全体のスキャンに
なります。
JOIN と GROUP BY を扱える DynamoDB の SQL クライアントはありますか?
はい — DynoTable の SQL Workbench はデスクトップから稼働中のテーブルに対して
JOIN/GROUP BY/集計を実行し、Amazon Athena は AWS アカウントにデプロイするフェデレーテッド
コネクタ経由でそれを行います。