SQL互換性と実行可能性
DSQLで同じ業務を実装するには何を変える必要があるか?
結果の要約
この実験では、既存のPostgreSQL業務をAurora DSQLへ移す際に、SQLをどの程度修正する必要があるかを確認しました。業務SQL 35項目を、DSQL(D1)と対照群の3サービス(RDS PostgreSQL、Aurora Provisioned、Aurora Serverless v2)でそのまま実行しました。DSQLは17項目を修正なしで通過し、16項目を「サポートされていない機能」(SQLSTATE 0A000)として拒否しました。対照群の3サービスは、DSQL専用構文であるCREATE INDEX ASYNCを除く34項目をすべて通過しました。
DSQLで修正が必要だった領域は、sequence・identityの宣言、serial型、インデックスの作成方法、一時テーブルとパーティション、PL/pgSQL関数とトリガー、分離レベルの指定、statement_timeout、サーバー側での文のキャンセルです。一方、PK・UNIQUE・CHECK・外部キーなどの制約、JOIN・CTE・window関数、JSONB、そして中核業務である注文トランザクションは元のまま動作しました。SELECT FOR UPDATEは構文としては通りましたが、動作が異なりました。対照群は他の書き込みを待機させましたが、DSQLは待機させず、コミット時点の競合(40001)で一方を失敗させました。したがって、DSQLへ移行するアプリケーションには、失敗したトランザクションを再試行するロジックが必要です。
この結果は、小型構成とローカルクライアントでSQL機能のみを検査したもので、各構成を1回ずつ実行しました。性能、レイテンシ、高可用性は評価しておらず、DSQLのサポート範囲は変わり続けるため、2026-09-24時点での観測として読む必要があります。
本番利用の観点
DSQLは制約・外部キー・JOIN・JSONBや注文トランザクションといった中核的なOLTP SQLを修正なしで実行したため、最初からDSQLの制約に合わせて設計する新規サービスであれば、SQL面での導入障壁は低いです。一方、既存のPostgreSQLサービスを移すには、sequence・serialの宣言、インデックスの作成方法、PL/pgSQL・トリガー、一時テーブル・パーティションを変更する必要があります。また、分離レベルはREPEATABLE READのみで、statement_timeoutとサーバー側のキャンセルが動作しないため、競合時の再試行とリクエストの期限をアプリケーションで実装する必要があります。ストアドプロシージャとトリガーにロジックが多いシステムほど、移行コストは大きくなります。この実験は機能検査にすぎず、性能・可用性はE002以降の実験で判断します。
確認する問い
DSQLで同じ業務を実装するには何を変える必要があるか?既存のPostgreSQL業務SQL 35項目をD1(Aurora DSQL)と対照群3種(R1 RDS PostgreSQL、A1 Aurora Provisioned、A2 Aurora Serverless v2)で実行し、構文が受け入れられるかどうかと、結果・不変条件が一致するかどうかを併せて判定しました。
実行条件
- 測定日:2026-09-24 UTC、リージョン
ap-northeast-2、実行prefixe001-20260924t071645z-d551。 - コードコミット:
dfbbe696da48df2df5434ee400c4386fff807197(4構成すべてで同じコード)。 - 構成(計画より縮小。SQL機能検査専用):
| ID | 実際の構成 | 計画構成との違い |
|---|---|---|
| D1 | DSQLシングルリージョンクラスター、admin IAMトークン、verify-full TLS |
なし |
| R1-lite | RDS PostgreSQL 16.15、db.t4g.micro、gp3 20 GiB、Multi-AZ |
クラス・ストレージを縮小 |
| A1-lite | Aurora PostgreSQL 16.15、db.t4g.medium writer 1台 |
readerなし、小型クラス |
| A2-lite | Aurora Serverless v2 16.15、writer 1台、0.5–2 ACU | readerなし、ACU範囲を縮小 |
- クライアント:ローカルPC(Python・psycopg)からパブリックエンドポイントへ接続しました。この接続経路のレイテンシは比較の根拠には使いません。
- 各項目は専用テーブルと新しい接続で実行し、ある項目の失敗が他の項目に影響しないようにしました。文ごとに30秒のクライアント側期限があります。
- 実行中の逸脱:R1のプロビジョニング中(07:20Z開始)に、実行を管理していたエージェントセッションが使用量制限により中断しました。インスタンスは作成が続き07:31Zに
availableとなったため、同じprefixのmanifestに接続情報を補ったうえで、run→cleanup→verifyを手動で続けて実行しました。検査コードと入力は変わっていません。R1がMulti-AZで作成されたことは、CloudTrailのCreateDBInstanceリクエスト(multiAZ=true)で確認しました。
性能結果
この実験は機能検査であり、スループット・レイテンシは測定していません(未測定)。項目ごとの判定結果は次のとおりです。passは構文の受け入れと意味検証の通過、unsupportedはSQLSTATE 0A000、rejected_needs_reviewは構文・オブジェクトのエラーで人が判定する必要がある場合、semantic_mismatchは文は受け入れられたものの期待した動作と異なる場合です。
| 判定 | D1 | R1 | A1 | A2 |
|---|---|---|---|---|
| pass | 17 | 34 | 34 | 34 |
| unsupported (0A000) | 16 | 0 | 0 | 0 |
| rejected_needs_review | 1 | 1 | 1 | 1 |
| semantic_mismatch | 1 | 0 | 0 | 0 |
R1・A1・A2のrejected_needs_review 1件はDSQL専用構文であるCREATE INDEX ASYNC(42601)で、PostgreSQLで拒否されるのは想定どおりの結果です。対照群3構成の間に違いはありませんでした。
DSQL(D1)で結果が分かれた項目:
| 項目 | D1の結果 | 観測内容 | 移植方法 |
|---|---|---|---|
CREATE SEQUENCE(既定CACHE)、GENERATED ... AS IDENTITY(既定CACHE) |
unsupported | 既定のCACHE値を拒否 | CACHE 65536を明示すれば通過 |
serial型 |
rejected (42704) | type "serial" does not exist |
identityまたはsequence(CACHE 65536)に変更 |
CREATE INDEX(B-tree・GIN・式) |
unsupported | “please use CREATE INDEX ASYNC” | B-treeはCREATE INDEX ASYNCで通過。GIN・式インデックスの代替は未検証 |
| 一時テーブル、範囲パーティション | unsupported | — | アプリケーション設計の変更が必要 |
| PL/pgSQL関数、トリガー | unsupported | SQL関数は通過 | ロジックをSQL関数またはアプリケーションへ移す |
SET TRANSACTION ISOLATION LEVEL ... 3種、BEGIN ISOLATION LEVEL READ COMMITTED/SERIALIZABLE |
unsupported | BEGIN ISOLATION LEVEL REPEATABLE READのみ受け入れ |
REPEATABLE READを前提にロジックを見直す |
statement_timeout(sleep・CPUの変形) |
unsupported | セッション設定を拒否 | クライアント側の期限で代替 |
| クライアントからのキャンセル | semantic_mismatch | pg_sleep(5)にキャンセル要求を送ったが、文が最後まで実行されて成功(期待値:57014) |
サーバー側の中断に依存しないよう処理の大きさを制限 |
DSQLで修正なしに通過した項目:PK/UNIQUE/CHECK、外部キー(孤立行の挿入と参照されている親の削除をいずれも23503で拒否)、UPSERT、JOIN/CTE/window、再帰CTE、JSONBの実行時利用・格納列、SQL関数、SELECT FOR UPDATE、REPEATABLE READでのlost update防止、共通の注文トランザクション(FKありの元版とFKなしの変形の両方で業務結果・不変条件が一致)。
SELECT FOR UPDATEは4構成すべてでlost updateなしに通過しましたが、動作の仕組みが異なります。シナリオは、接続Aが行をFOR UPDATEでロックして+1の更新を行い、その間に接続Bが同じ行に+10の更新を試みるというものです。R1・A1・A2では、BはAのコミットまで待機し、両方の更新が反映されました(100 → 111)。D1では、Aがロックを保持している間にBの書き込みが先に完了し、Aがコミット時点で40001(直列化の競合)により失敗して、Aの更新がロールバックされました(100 → 110)。つまりDSQLのFOR UPDATEは他の書き込みを待機させず、コミット時点の競合によって整合性を守るため、同じ業務結果を得るには失敗したトランザクションを再試行するロジックがアプリケーションに必要です。競合条件での整合性と再試行のコストはE004で検証します。
開発・運用のしやすさ
- 準備時間(作成リクエストから接続可能になるまで):D1 16秒、A1 約5分、A2 約7分、R1 約12分(Multi-AZへの切り替えを含む)。削除(リクエストから削除完了の確認まで):D1 約1.5分、R1 約3.5分、A1 約6.5分、A2 約6分。
- D1にはVPC・サブネット・セキュリティグループ・DBパスワードなしに、IAMトークンで接続しました。対照群は構成ごとにVPC、サブネット2つ、IGW、セキュリティグループ、DBサブネットグループを作成し、パスワードを管理する必要がありました。
- 一方、既存のスキーマ・SQLをDSQLへ移すには、上の表の修正(sequenceのCACHE、
serialの除去、インデックスのASYNC化、PL/pgSQL・トリガーの移設、分離レベル・timeout処理の変更、40001の再試行)が必要です。修正作業にかかる時間は今回の実験では測定していません。 - 上記の時間は1回の実行の値であり、繰り返し測定による変動は確認していません。
費用
単価は2026-09-24にAWS Price List APIで確認したソウルリージョンのOn-Demand価格です。下の表の推定は、作成リクエストから削除完了までを稼働時間の上限としたもので、実際の請求額は2026-09-28にCost Explorer(ソウルリージョン、2026-09-24 UTC、使用タイプ別)で確認した値です。
| 構成 | 稼働時間(上限) | 単価 | 推定 | 実際の請求額 |
|---|---|---|---|---|
| D1 | DSQLクラスターの作成から削除まで約2分 | $0.00001/DPU | パイロット1回の57 DPUで約$0.0006(比較実行のDPUは未収集) | $0(DSQLの月間無料使用量の範囲内) |
| R1 | 15.9分 | $0.051/時間(db.t4g.micro Multi-AZ) | 約$0.014 | 約$0.012(ストレージを含む) |
| A1 | 12.0分 | $0.113/時間(db.t4g.medium) | 約$0.023 | 約$0.019(10分の最低課金) |
| A2 | 13.0分 | $0.20/ACU時間 | 0.5–2 ACUの範囲で約$0.022–0.087 | 約$0.048(0.217 ACU時間、Aurora I/Oを含む) |
推定の際は、ストレージ、Aurora I/O、パブリックIPv4の料金は少額のため除外し、合計を約$0.06–0.13と見積もりました。実際の請求額の合計は約$0.08で、推定範囲内でした。A1は実際の稼働が10分未満だったため、RDSの最低課金時間である10分(0.167時間)で請求されました。
結論と限界
- 結論:今回の35項目を基準にすると、DSQLは17項目(49%)を修正なしで実行し、対照群の3サービスはPostgreSQLの機能項目をすべて通過しました。DSQLへ移す際に修正が必要な領域は、sequence・identityの宣言、
serial、インデックスの作成方法、一時テーブル・パーティション、PL/pgSQL・トリガー、分離レベルの指定、statement_timeout、サーバー側での文のキャンセルです。中核の業務フローである注文トランザクションは、FKを含む元のままDSQLで通過しました。 - DSQLのFKサポートは、今回の実測(2026-09-24)で観測された動作です。DSQLのサポート範囲は変わり続けるため、別の時点では結果が異なる可能性があります。
- 限界:ローカルクライアントと小型構成による機能検査であり、レイテンシ・スループット・HAは評価していません。各構成1回の実行です。
SELECT FOR UPDATEと分離レベルは、2接続による単一シナリオでの観測です。ORMのスキーマ変更と論理レプリケーション/CDCは未測定です。GIN・式インデックスのDSQLでの代替方法は検証していません。
後片付けの記録
- 削除対象:D1のDSQLクラスター1つ、R1・A1・A2それぞれのDBインスタンス(AuroraはDBクラスターを含む)、DBサブネットグループ、セキュリティグループ、サブネット2つ、IGW、VPC。
- 後片付け完了時刻(UTC):D1 07:18:46、R1 07:35:56、A1 07:48:12、A2 08:01:18。すべての削除段階で失敗はありませんでした。
- 検証:08:01:37Zに実験ツールの
verifyで、このprefixのmanifestリソース、スナップショット、保持された自動バックアップ、タグ付きEC2リソースを照会し、remaining_count=0を確認しました。パイロットprefix(e001-20260924t071247z-cf9e)も08:01:38Zに0件であることを確認しました。さらに、アカウント全体でe001接頭辞のDBインスタンス・クラスター・クラスタースナップショット、DSQLクラスター、e001:run-prefixタグのVPCを照会し、いずれも0件であることを確認しました。