1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「いま重い SQL を 3 件教えて」を Claude から Aurora に聞いてみた:MCP でつなぐ pg_stat_statements と Database Insights

1
Posted at

1. はじめに

これまで Oracle Database を相手に、「いま重い SQL を 3 件教えて」という同じ質問を、SELECT AI・SQLcl MCP・OCI Database Tools MCP など公式 4 経路に投げ比べる検証を重ねてきました12。DB に自然言語で性能診断を頼むとき、どの経路(ツール)が選ばれ、どこまで深掘りできるのかを見る検証です。

今回はその Aurora PostgreSQL 版です。Oracle には V$SQL(DB 内の SQL 統計)と AWR / ASH(マネージドな診断データ)がありましたが、Aurora で「重い SQL」を答えられる経路は次の 2 本と考えました。

  • 経路1: pg_stat_statements。PostgreSQL 標準の累積 SQL 統計ビュー3。SQL 実行型の MCP サーバー(awslabs postgres-mcp-server4)の run_query で読む
  • 経路2: CloudWatch Database Insights(旧 Performance Insights)。DB Load(Average Active Sessions、以下 AAS)を時系列で持つマネージド診断56。汎用 API 型の MCP サーバー(AWS API MCP Server7)の call_aws などから aws pi コマンドで叩く

経路2 の名前について先に補足します。旧称 Performance Insights のコンソール画面は 2026 年 7 月 31 日で終了し、CloudWatch Database Insights に統合されることが告知されています。一方で、データ取得の API は Performance Insights API のまま「変更なしで存続」 と公式に明記されています5。エージェントから叩くのはこの API です。本記事では、サービスを Database Insights、API とコマンドを PI(aws pi)と表記します(詳細は 5 章冒頭の補足)。

この 2 本それぞれに、そして両方をつないだ状態で、同じ 3 ターンの質問を投げてどう振る舞うかを実機で確かめました。以降、3 つの質問を T1「いま重い SQL を 3 件教えて」、T2「1 番上の SQL の実行計画を見せて」、T3「この SQL のチューニング案を出して」と呼びます。

1.1. 今回の検証ゴール

# 検証項目 達成できたとみなす条件
1 意図した「重い SQL」を経路1(pg_stat_statements)と経路2(PI)の両方の上位に出す 仕込んだ 3 本の SQL が両方の Top3 に入り、順位が再現する
2 経路1 で 3 ターン会話(T1→T2→T3)が完了する Top3、実行計画、チューニング案が会話の中で返る
3 経路2 で同じ 3 ターンに答えられるか、限界(実行計画を持たない等)にどう対処するかを観測する T1 で PI 由来の Top3 が返り、T2 以降の挙動を記録できる

1.2. 結論(先出し)

  • 仕込んだ 3 本の重い SQL は、pg_stat_statements(累積実行時間)でも PI(AAS)でも 同じ順位の Top3 になった。物差しが違っても答えは一致する
  • 経路1 の 3 ターンは完走。readonly の MCP では EXPLAIN ANALYZE が拒否され、コスト見積もりだけの EXPLAIN に自動で切り替わった
  • 経路2 は T1 に答えられるが、実行計画は持っていない。実行計画を求められた会話は Secrets Manager から接続情報を自分で見つけて psql を組み立て、SQL を実行する手段を自作した
  • 両方つないだ状態の T1 は、4 回中 3 回が pg_stat_statements 側。SQL を実行できる手段があるなら SQL で聞くのが今回のクライアントの基本の動きだった
  • DB への到達可否を最終的に決めていたのは MCP のツール構成ではなく IAM 権限。この整理は考察(7.3 章)で述べる

2. 検証環境

項目 内容
Aurora PostgreSQL 17.9 / Serverless v2(MinCapacity 0.5〜2.0 ACU)/ 東京リージョン
クラスタ topsql-cluster / インスタンス topsql-instance-1(db.serverless)/ データベース appdb
モニタリング Performance Insights 有効(= Database Insights の Standard モード・保持 7 日は無料枠8
経路1 の MCP awslabs.postgres-mcp-server 1.1.7(readonly、RDS Data API 接続)
経路2 の MCP awslabs.aws-api-mcp-server 1.3.46(READ_OPERATIONS_ONLY=true
会話クライアント Claude Desktop の Code モード(モデル claude-sonnet-5 / 推論 effort medium で統一)
負荷ツール pgbench(scale 15 = pgbench_accounts 150 万行)+ カスタムの重い SQL 3 本

会話クライアントについて 1 点補足します。今回の 3 ターン会話は Claude Desktop の Code モード(ローカルの Claude Code セッション)で実施しました。通常のチャットと違い、Code モードは MCP ツールに加えてローカルのファイル読み取りやシェル実行も使えます。後で見るとおり、この条件が会話の振る舞いに大きく影響しました。同じ質問でも、チャット + コネクタ構成のクライアントとは違う結果になりうる点は先に断っておきます。

3. 重い SQL を仕込む

3.1. 環境の作成

環境は検証のたびに作って壊す方針です。作成手順はコマンドの流れの要点だけ載せます。

# クラスタ(Serverless v2・MinACU 0.5 でゼロスケールさせない)
aws rds create-db-cluster \
  --db-cluster-identifier topsql-cluster \
  --engine aurora-postgresql --engine-version 17.9 \
  --master-username postgres --manage-master-user-password \
  --serverless-v2-scaling-configuration MinCapacity=0.5,MaxCapacity=2.0 \
  --database-name appdb ...

# インスタンス(Performance Insights 有効・保持 7 日)
aws rds create-db-instance \
  --db-instance-identifier topsql-instance-1 --db-cluster-identifier topsql-cluster \
  --engine aurora-postgresql --db-instance-class db.serverless \
  --enable-performance-insights --performance-insights-retention-period 7 ...

# Data API を有効化(経路1 の MCP が RDS Data API 接続のため)
aws rds enable-http-endpoint --resource-arn <クラスタの ARN> ...

MinCapacity を 0.5 にしてゼロスケールさせないのは、自動停止すると PI の計測が途切れ、pg_stat_statements もリセットされるためです。また Serverless v2 の Data API 有効化は modify-db-cluster --enable-http-endpoint ではなく enable-http-endpoint API を使います。前者は Serverless v1 用で、v2 クラスタにはエラーも出ずに無視されました9

pg_stat_statements は Aurora PostgreSQL では最初から shared_preload_libraries に含まれているため、拡張を作るだけで使えます10

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

3.2. 重い SQL 3 本

pgbench の標準負荷だけだと Top SQL が細かい UPDATE 文に埋もれるので、識別しやすいタグ付きの重い SQL を 3 本用意しました。すべて pgbench_accounts(150 万行)の全走査になります。

-- q1: 集計(式で GROUP BY + ORDER BY でソートを強制)
SELECT /* topsql-q1-agg */ (abalance / 500)::int AS bucket, count(*) AS c, sum(abalance) AS s
FROM pgbench_accounts
GROUP BY 1
ORDER BY c DESC
LIMIT 50;

-- q2: 結合+集計(branches と JOIN して bid ごとに集約)。今回の最重量
SELECT /* topsql-q2-join */ a.bid, count(*) AS c, avg(a.abalance) AS avg_bal, max(a.abalance) AS max_bal
FROM pgbench_accounts a
JOIN pgbench_branches b ON a.bid = b.bid
GROUP BY a.bid
ORDER BY c DESC;

-- q3: DISTINCT(非索引列の重複排除で大きなハッシュ処理)
SELECT /* topsql-q3-distinct */ count(*) AS distinct_bal
FROM (SELECT DISTINCT abalance FROM pgbench_accounts) d;

これを pgbench のカスタムスクリプトとして流します。標準負荷(60 秒)で OLTP らしい背景を作ってから、重い SQL を 4 クライアント並列で 150 秒実行しました。

pgbench -h <エンドポイント> -U postgres -d appdb -c 4 -j 4 -T 60      # 標準負荷
pgbench -h <エンドポイント> -U postgres -d appdb -f heavy_queries.sql -c 4 -j 4 -T 150 -n

3.3. 2 つの経路で同じ Top3 が出るか

まず会話に入る前に、素の psql と AWS CLI で両方の統計を確認しました。経路1 側、pg_stat_statements を累積実行時間の降順で見た上位です。

順位 クエリ(タグ) calls 総実行時間 平均実行時間
1 topsql-q2-join 126 回 264,044 ms 2,095.6 ms
2 topsql-q1-agg 126 回 182,209 ms 1,446.1 ms
3 topsql-q3-distinct 126 回 152,330 ms 1,209.0 ms
4 UPDATE pgbench_accounts ...(標準負荷) 12,614 回 20,957 ms 1.7 ms

仕込んだ 3 本が、1 万回以上呼ばれた OLTP の UPDATE 群を総実行時間で大きく上回りました。SQL テキストは $1 の形に正規化されて集計されます。

経路2 側、PI の db.load.avgdb.sql_tokenized(正規化 SQL)でグループ化した上位です。負荷実行中の DB Load はピークで AAS 3.93 まで上がっていました(4 クライアント並列なのでほぼ理論値です)。

順位 クエリ(正規化) DB Load(AAS)
1 topsql-q2-join 0.494
2 topsql-q1-agg 0.337
3 topsql-q3-distinct 0.278
4 END(トランザクション終端) 0.106

両経路とも Top3 は q2 > q1 > q3 の同順でした。片方は「総実行時間の累積」、もう片方は「その時間帯にアクティブだったセッションの平均数」という別の物差しですが、同じ答えに収束しています(理由は 7.1 章)。ゴール 1 はここで達成です。なお PI の上位に END が入るのは、トランザクション終端がサンプリングで拾われる PI 特有のノイズで、pg_stat_statements 側には出ません。

環境は検証期間中に一度削除して作り直しましたが、同じ手順・同じ負荷で作り直した 2 回目も Top3 の顔ぶれと順位はそのまま再現しました。

3.4. つまずいた点: postgres-mcp の接続方式

当初、経路1 の postgres-mcp-server は PostgreSQL プロトコルでの直接接続(起動引数 --connection_method PG_WIRE_PROTOCOL)で設定していました。ところがこの構成では、会話の最初の run_query から次のエラーで全ツールが失敗します。

RuntimeError: <aiorwlock._RWLockCore object at 0x...> is bound to a different event loop

プロセスを再起動しても直らず、会話中の再接続ツールでも回復しませんでした。今回検証したバージョン 1.1.7 では、起動時の接続検証とツール実行が別のイベントループで動くことが原因で、CLI 引数でこの接続方式を渡すと常に発生します。回避策として、クラスタの Data API を有効化して --connection_method RDS_API(Data API 接続)で起動する構成に切り替えました。切り分けの詳細は別記事にまとめる予定です。

4. 経路1: pg_stat_statements を MCP で読む

postgres-mcp-server と aws-api-mcp-server の両方をつないだ新規セッションで、T1 から順に投げます。この章では、pg_stat_statements を読む経路1 が選ばれた会話を追います。

4.1. T1「いま重い SQL を 3 件教えて」

会話はまず call_aws でクラスタの稼働を確かめ、作業フォルダにあった設定ファイルで接続先を確認してから、run_querypg_stat_statements を読みました。返ってきたのがこの表です。

経路1 の T1。pg_stat_statements から Top3 を取得

順位 クエリ(タグ) 呼び出し回数 合計実行時間 平均実行時間 全体に占める割合
1 topsql-q2-join 272 回 591,170.7 ms 2,173.4 ms 43.8%
2 topsql-q1-agg 272 回 402,119.9 ms 1,478.4 ms 29.8%
3 topsql-q3-distinct 272 回 332,676.7 ms 1,223.1 ms 24.6%

3 本で累積実行時間の約 98% を占める、という補足まで付きました。人手なら ORDER BY total_exec_time DESC LIMIT 3 を書くだけの操作ですが、割合の計算やタグの読み取りまで含めて 1 ターンで返ってきます。

4.2. T2「1 番上の SQL の実行計画を見せて」

続けて実行計画を頼むと、会話はまず EXPLAIN (ANALYZE, BUFFERS) を実行しようとして、MCP の readonly 制約に拒否されました。

Your MCP tool only allows readonly query. If you want to write, change the MCP configuration per README.md

postgres-mcp-server の readonly は SQL キーワードのブロックリストで実装されており、ANALYZE を含む文は書き込み扱いになります。会話はここで止まらず、実行を伴わない素の EXPLAIN に切り替えて計画を取得しました。

経路1 の T2。EXPLAIN ANALYZE が拒否され、素の EXPLAIN に切り替えて取得

Sort  (cost=40349.48..40349.52 rows=15 width=48)
  Sort Key: (count(*)) DESC
  ->  Finalize GroupAggregate  (cost=40345.20..40349.19 rows=15 width=48)
        ->  Gather Merge  (cost=40345.20..40348.70 rows=30 width=48)
              Workers Planned: 2
              ->  Partial HashAggregate
                    ->  Hash Join  (cost=1.34..33080.08 rows=626465 width=8)
                          ->  Parallel Seq Scan on pgbench_accounts a
                          ->  Hash -> Seq Scan on pgbench_branches b

pgbench_accountsbid の索引が無いため、並列の全件走査(Parallel Seq Scan)とハッシュ結合になっている、という読み解きも付いてきました。コスト見積もりだけでも T2 の答えとしては十分です。ただし実測の実行時間やバッファ読み取りは readonly の接続からは取れません(この続きは 5.3 章で別の形で回収されます)。

4.3. T3「この SQL のチューニング案を出して」

チューニング案の前に、会話は pg_indexes で既存の索引を確認してから答えました。提案は 3 つです。

経路1 の T3。索引の実態を確認した上でのチューニング案

  1. JOIN の削除。このクエリは pgbench_branches から列を 1 つも参照しておらず、結合は集計結果を変えずに削除できる
  2. カバリングインデックスCREATE INDEX ... ON pgbench_accounts (bid) INCLUDE (abalance) で Index Only Scan に変えられる可能性がある
  3. 統計情報の確認。dead tuple が溜まるとプランナの見積もりがずれるため、pg_stat_user_tables の確認と ANALYZE を先に

いずれも直前に取得した実行計画と索引の実態に基づいた提案で、readonly のため「実行はできないので、試すなら書き込み許可か psql で」という限定も添えられていました。ゴール 2 はここで達成です。

4.4. 補足: pg_stat_statements は「いま」ではなく「累積」

この会話の後、負荷を止めた状態で T1 をもう一度投げてみました。返ってきた Top3 は同じ顔ぶれのまま呼び出し回数だけが増えており、さらにもう一度聞くと「calls も数値も前回と同一なので、新しい実行は発生していません」という指摘が返ってきました。

pg_stat_statements はリセットするまでの累積統計なので、「いま重い SQL」という質問の「いま」には本来答えていません。負荷が止まった後でも過去の重い SQL が上位に残り続けます。この性質は、時系列を持つ PI との使い分けを考えるときの軸になります(7.2 章)。

5. 経路2: Database Insights(PI API)をエージェントから叩く

Performance Insights と CloudWatch Database Insights
AWS は Performance Insights のコンソール体験を 2026 年 7 月 31 日で終了し、CloudWatch Database Insights に統合すると告知しています。何もしない場合、既存の DB は保持期間そのままで Database Insights の Standard モードに移行し、Performance Insights の API は「変更なしで存続」と明記されています5。実際、今回作成したクラスタの describe-db-clusters 応答にも DatabaseInsightsMode: standard が付いていました。本章で使う aws pi describe-dimension-keys などは、この存続する API です6

次に経路2 です。経路1(postgres-mcp-server)が見えないセッションで同じ質問を投げました。

5.1. T1: call_aws で PI の Top SQL を取る

会話は aws pi describe-dimension-keys を組み立てて実行しました。指標は db.load.avg、グループ化は db.sql_tokenized です。

経路2 の T1。call_aws で PI から Top3 を取得

順位 クエリ(正規化) DB Load(AAS)
1 topsql-q2-join 0.1023
2 topsql-q1-agg 0.0709
3 topsql-q3-distinct 0.0599

--metric-queries--group-by の JSON 引数を LLM が作れるかを事前に心配していましたが、1〜2 回の引数エラーを自分で修正して到達しました。経路1 と同じ q2 > q1 > q3 です。

なお PI の API が返す SQL テキストは 500 バイトまでで、全文が必要な長い SQL では GetDimensionKeyDetails を併用する必要があります11。今回の 3 本はいずれも 500 バイト未満だったため、全文がそのまま取れています。

5.2. PI は「負荷が走った時刻」を含む時間範囲で聞く必要がある

経路2 で注意が要るのは、取得時に指定する時間範囲(--start-time--end-time)です。負荷を止めてから約 70 分後に別のセッションで T1 を投げたところ、直近 1 時間の範囲では「実質的な負荷はほぼ皆無(autovacuum のみ)」という回答になりました。会話はそこで止まらず、範囲を過去 24 時間に広げて同じ Top3(q2 0.121 > q1 0.083 > q3 0.070)を取り直しています。

指定した時間範囲に負荷が無く、24 時間に広げて再取得した回答

pg_stat_statements が「累積しすぎる」のとは逆に、PI は「負荷のあった時間帯を外すと何も出ない」性質です。DB Load の時系列(get-resource-metrics)で負荷の山を先に確かめてから、describe-dimension-keys に渡す時間範囲を決めるのが確実です。

5.3. T2: 実行計画を持たない PI と、SQL 実行手段を自作する会話

経路2 の一番の見どころが T2 です。PI は待機イベントや Top SQL は持っていますが、実行計画は持っていません。SQL を実行する手段が無いセッションで「実行計画を見せて」と頼むとどうなるか。

会話の答えは「実行計画を取得するには実際に DB へ接続して SQL を実行する必要があります」でした。そしてここからが想定外で、会話は次の手順を自分で組み立てました。

  1. Secrets Manager を list-secrets で探索し、クラスタの管理下にあるマスターユーザーシークレットを発見する
  2. シークレットの値を環境変数 PGPASSWORD として渡すシェルスクリプトを書く(パスワードは画面に出さない配慮つき)
  3. psql で EXPLAIN (ANALYZE, BUFFERS) を実行する

Secrets Manager から接続情報を見つけて psql で実行計画を取得

実行時間: 1,202 ms(プランニング 31 ms 込み)
Parallel Seq Scan on pgbench_accounts(3 ワーカー・約 150 万行)
バッファ: shared hit=11,072, read=13,633

つまり経路2 単独のセッションは、実行計画を諦める代わりに、Secrets Manager + psql で SQL を実行する手段そのものを自作しました。しかも皮肉なことに、マスターユーザーで直接接続した psql には MCP の readonly 制約が無いため、経路1 では拒否され続けた EXPLAIN ANALYZE(実測値付き)が、この経路だけで取れています。

T3 のチューニング案も、この自作した接続で pg_stat_user_tablesshared_buffers まで確認した上で返ってきました。バッファ読み取りの 13,633 ブロックがディスク由来である原因を「shared_buffers 128 MB がテーブルサイズ 193 MB より小さい」と特定し、カバリングインデックスに加えて Serverless v2 の MinCapacity 引き上げまで提案しています。

自作した接続で統計まで確認した上でのチューニング案

これは有用な動きであると同時に、権限設計の観点では見過ごせない挙動です。この整理は 7.3 章に回します。ゴール 3 は「T1 は達成、T2 は限界への対処として SQL 実行手段の自作を観測」という結果になりました。

6. 両方つないで「重い SQL」を聞く

最後に、両方の MCP をつないだ新規セッションで T1 だけを投げる観測を繰り返しました。どちらの経路が選ばれるかの記録です。

会話(すべて新規セッション) T1 で選ばれた経路 経緯
両方 ON・1 回目 経路1(pg_stat_statements) 接続情報のキャッシュを見つけて run_query
両方 ON・2 回目 経路1(pg_stat_statements) call_aws で稼働確認、設定ファイルで接続先を確認して run_query
両方 ON・3 回目 経路1(pg_stat_statements) pg_stat_activity で「実行中」を先に確認、空だったので累積へ
両方 ON・経路2 を指定 経路2(PI) ユーザーが「PI 側を試したい」と答えた場合のみ

自発的な選択は 3 回とも経路1 でした。理由として観察できたのは、postgres-mcp-server が保持する接続情報のキャッシュの存在です。会話は最初に「どの DB につながるか」を確かめに行き、すぐ使える SQL の接続を見つけると、そのまま SQL で答えを取りに行きます。PI が自発的に選ばれたのは、SQL 経路がそもそも見えないセッション(5 章)だけでした。

3 回目の会話は選び方も丁寧でした。「いま重い SQL」の「いま」を文字どおりに受け取り、まず pg_stat_activity で実行中のクエリを確認し、全セッションが待機中と分かってから累積統計に切り替えて「現在アクティブに実行中のクエリはありません」という限定付きで Top3 を返しています。さらに、呼び出し回数がすべて同じ 487 回であることから「ベンチマークスクリプトによる周期実行と見られます」と、負荷の性質まで言い当てました。

両方 ON の 3 回目。実行中の確認から累積へのフォールバック

観測方法についても 1 点正直に書いておきます。今回のクライアント(Code モード)はローカルのファイルも読めるため、T1 の直後に作業フォルダの検証メモを読んで「これはツール選択の実験ですね」と気づいた会話が 1 つありました(この会話は観測から除外しています)。表の 3 つの会話が実験の設計メモを読んでいないことは、ツール呼び出しの記録で確認しています(2 回目の会話が読んだのは接続先の設定ファイルだけです)。また経路2 の一部の観測(5.2 章・5.3 章)は、メモの無い空のフォルダでセッションを作って実施しました。エージェントの挙動を観測するとき、観測対象が実験手順書を読める環境かどうかは結果を左右する条件でした。

7. 考察

7.1. 物差しが違うのに Top3 が一致した理由

経路1 は総実行時間の累積、経路2 は AAS という別の指標ですが、Top3 は常に q2 > q1 > q3 で一致しました(3.3 章・4.1 章・5.1 章)。今回の負荷は 3 本とも CPU 中心の全件走査で、同じ並列度(4 クライアント)で同じ回数実行されています。この条件では「1 回あたりの実行時間が長い SQL ほど、その分アクティブでいる時間も長い」という関係がそのまま成り立つため、累積時間の順位と AAS の順位が揃ったと考えられます。待機(ロックや I/O 待ち)が支配的な負荷では、この 2 つの物差しの順位が食い違う可能性があります(未検証)。

なお Aurora PostgreSQL の PI が表示する SQL 統計自体、内部的には pg_stat_statements 由来の値を使っています12。2 つの経路は無関係ではなく、同じ計測基盤を「累積で読むか、時系列サンプリングで読むか」の違いと整理できます。

7.2. 観点ごとに 2 経路の性格を整理する

pg_stat_statements と PI の性格を観点ごとに整理し、Oracle 側の過去検証12での対応も添えました。

観点 経路1: pg_stat_statements 経路2: Database Insights(PI API) Oracle だと何にあたるか
データの性質 累積(リセットまで残る) 時系列(負荷の時間帯を外すと出ない) V$SQL(累積)/ AWR・ASH(時系列)
LLM の自由度 高い。任意の SELECT を書ける 低い。API の引数を組み立てる SQL 実行系 MCP / 固定 API 系と同じ構図
認証・認可 DB のロールと MCP の readonly IAM の pi:* 読み取り権限 DB ユーザー権限 / OCI の IAM
深掘り耐性(T2・T3) 高い。EXPLAIN・カタログまで届く 単独では実行計画に届かない 汎用 SQL 経路が深掘りに強いのも同じ
向く読者 SQL を書ける DBA・開発者 AWS 運用者。DB 接続情報を配らずに済む 4 経路の使い分けと同じ発想

Oracle の検証で見えていた「深掘りは汎用 SQL 経路が強い」「ツール選択は、すぐ使える接続がある経路に寄る」という傾向は、Aurora の 2 経路でもそのまま再現しました。一方で Oracle と違うのは、Aurora には SELECT AI のような DB 内蔵の自然言語問い合わせ機能が無いことです。エージェント側(クライアント側)が SQL を書いて経路1 を使う形が、実質その代わりになっています。

7.3. 到達可否を決めていたのは MCP ではなく IAM

5.3 章の挙動をもう一度見ます。SQL 経路(postgres-mcp-server)を外したセッションは、Secrets Manager からマスターユーザーシークレットを見つけ、psql で DB に接続しました。これができたのは、実行環境の AWS 認証情報に secretsmanager:GetSecretValue の権限があり、ネットワーク的にも 5432 番ポートへ到達できたからです。

つまり「MCP サーバーを readonly にする」「SQL 実行系の MCP を外す」といったツール側の構成は、ツール経由の操作を制限するだけで、DB への到達そのものを防ぐ境界ではありません。実際、MCP の readonly が拒否し続けた EXPLAIN ANALYZE を、MCP を介さない自作の psql はそのまま実行できました。到達可否を決めていたのは IAM 権限とネットワーク(セキュリティグループ)です。

この整理は DynamoDB の MCP サーバーを検証したときの「READ_OPERATIONS_ONLY はツール経由の操作までを守る」という結論13と同じ形です。付け加えると、SQL を実行する手段を自作する動きは MCP サーバーの機能ではなく、シェルが使える今回のクライアント(Code モード)でのモデルの判断です。別のクライアントや、シェルの無い構成では起きません。エージェントに DB 診断を任せる環境を設計するなら、「どの MCP をつなぐか」より先に「その実行環境の IAM とネットワークで、どこまで届いてよいか」を決めるのが順序だと考えます。

8. まとめ

# 検証項目 結果
1 重い SQL を両経路の上位に出す 達成。pg_stat_statements と PI の Top3 が同順(q2 > q1 > q3)で一致し、環境を作り直しても再現した
2 経路1 で 3 ターン完了 達成。EXPLAIN ANALYZE は readonly に拒否され、素の EXPLAIN で計画取得。索引確認つきのチューニング案まで返った
3 経路2 の 3 ターンと限界の観測 T1 は PI で達成。実行計画は PI に無く、会話は Secrets Manager + psql で SQL を実行する手段を自作した。境界は MCP でなく IAM という整理を得た

「いま重い SQL を 3 件教えて」に対する Aurora の 2 つの経路は、それぞれ性格がはっきりしていました。pg_stat_statements は累積で深掘りに強く、PI は時系列で「いつ重かったか」に強い。そして両方をつないだエージェントは、迷わず SQL 経路を選びました。

振り返ると、ツール選択を厳密に比べるなら、Claude Desktop 側の条件はもっとそろえるべきでした。ただ、3 つの検証ゴールはいずれも達成できていますし、実行計画が無いと分かってから psql を自分で組み立てるなど、LLM が状況に応じて手順を組み立てていく動きも面白かったので、測り直さずに観測をそのまま残しています。

参考

  1. 「いま重い SQL を 3 件教えて」を Claude × Oracle 公式 4 経路で 3 ターン会話してみた. https://qiita.com/asahide/items/931a4d782f2cd986af45 2

  2. 「いま重い SQL を 3 件教えて」を聞ける Oracle 公式 4 経路の横ぐし比較. https://qiita.com/asahide/items/860979ed23305aa4003b 2

  3. PostgreSQL Documentation, pg_stat_statements. https://www.postgresql.org/docs/current/pgstatstatements.html

  4. AWS Labs MCP, Amazon Aurora Postgres MCP Server. https://awslabs.github.io/mcp/servers/postgres-mcp-server

  5. Amazon Aurora ユーザーガイド, Amazon Aurora での Performance Insights による DB 負荷のモニタリング(ページ冒頭の Important に、コンソール体験の 2026 年 7 月 31 日終了・CloudWatch Database Insights への統合・「The Performance Insights API will continue to exist with no changes」の告知). https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/USER_PerfInsights.html 2 3

  6. Amazon CloudWatch ユーザーガイド, CloudWatch Database Insights. https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/monitoring/Database-Insights.html 2

  7. AWS Labs MCP, AWS API MCP Server. https://awslabs.github.io/mcp/servers/aws-api-mcp-server

  8. Amazon RDS Performance Insights の料金(7 日間の保持は無料利用枠). https://aws.amazon.com/jp/rds/performance-insights/pricing/

  9. Amazon Aurora ユーザーガイド, RDS Data API の使用(EnableHttpEndpoint). https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/data-api.html

  10. Amazon Aurora ユーザーガイド, aurora_stat_statements の使用. https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/aurora_stat_statements.html

  11. Amazon RDS Performance Insights API Reference, DescribeDimensionKeys(SQL テキストは 500 バイトで切り詰め。全文は GetDimensionKeyDetails で取得). https://docs.aws.amazon.com/performance-insights/latest/APIReference/API_DescribeDimensionKeys.html

  12. Amazon Aurora ユーザーガイド, Aurora PostgreSQL の SQL 統計. https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/AuroraUserGuide/USER_PerfInsights.UsingDashboard.AnalyzeDBLoad.AdditionalMetrics.PostgreSQL.html

  13. awslabs DynamoDB MCP Server を試した(READ_OPERATIONS_ONLY の境界整理). https://qiita.com/asahide/items/4911953d27b74269689b

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?