1. はじめに
前回、Aurora PostgreSQL で「いま重い SQL を3件教えて」と Claude に聞き、2つの経路でどう答えが返るかを実測しました。ひとつは PostgreSQL の拡張 pg_stat_statements(以下 pgss。クエリごとの累積実行時間を持つ)、もうひとつは AWS の Database Insights1(以下 DI。DB 負荷を AAS=同時アクティブセッション数の時系列で見る)です。この2経路の読み方や、正常/異常の判定基準、時間範囲や権限の注意点は、検証②の作業メモ(knowledge.md)に書き留めておきました。
今回はその続きで、この作業メモの中身を Claude の Agent Skill(診断ランブック)にすると、「いま重い SQL」への答えはどう変わるのかを実測します。ランブックを持たせない場合・取得手順だけの簡易ランブック・判定基準や改善策まで書いた詳細ランブックの3条件を、同じモデル・同じ質問・同じ負荷で並べて比べます。
1.1. 検証ゴール
| # | 確認したいこと | OK の条件 |
|---|---|---|
| 1 | 診断ランブックを Skill 化し、会話で使われるか | 応答にランブックの手順・判定基準が反映される(起動の扱いは 2.2 章のとおり) |
| 2 | 無/簡易/詳細の3条件で答えが変わるか | ツール選択・判定の根拠・改善策の3観点で、3条件間の差の有無が具体例つきで確定する |
| 3 | 差がどこに出るかを分類できるか | 各差分を「データ取得 / 解釈・判定 / 改善策」のどれかに分類でき、「Skill が差を生むのは解釈・改善策」という仮説の支持/不支持が決まる |
1.2. 結論(先出し)
- 答えの中身(重い SQL 3件・実行計画・チューニング案)は 3条件でほぼ同じに揃った。土台のモデル(claude-sonnet-5)が元々かなり答えられる
- 詳細ランブックで最も差が出たのは「解釈」の部分。上位3件が総実行時間の何 %を占めるか、累積と AAS は別の物差しである、といった判定基準を明示的に当てるようになった
- 簡易ランブックはむしろ取得を減らした。「実行計画は EXPLAIN で(実行せず計画のみ)」という一文に忠実に従い、ランブック無しなら取れていた実測 I/O を取り損ねた
- つまり 「Skill を持たせるか」より「ランブックをどう設計するか」で差が出る。取得はモデルに任せ、Skill には判定基準・既知の注意点・改善策の対応表という「判断の知識」を持たせるのが噛み合う
Agent Skills の公式ドキュメントは、Skill を「必要に応じて段階的に読み込む」仕組みだと説明しています2。名前と説明文(description)は常時読み込まれ、本文(SKILL.md)は関連する場面で初めて読み込まれる、という設計です。この「本文が読み込まれた状態」で答えがどう変わるかを見ていきます。
2. 検証環境
2.1. 環境と回答役
| 項目 | 内容 |
|---|---|
| 対象DB | Amazon Aurora PostgreSQL 17.9 / Serverless v2(Min 0.5・Max 2.0 ACU)/ Database Insights 有効 |
| 回答役(クライアント) | Claude のサブエージェント(Claude Code の Agent 機能で起動)。ローカルの Read/Bash が使える |
| 実行モデル | claude-sonnet-5(全条件で固定。検証②の会話と同一) |
| データ取得の土台 | WSL 上の psql(SQL 実行用ラッパ pgtool.sh)と AWS CLI(aws pi 用ラッパ pi.sh) |
| 負荷 | pgbench 標準(8クライアント・60秒)+ 意図的に重い SQL 3種(4クライアント・150秒。全件集計・JOIN・DISTINCT) |
| 比較条件 | ランブック無し / 簡易ランブック / 詳細ランブック の3条件 |
検証②では回答役を Claude Desktop の「Code モード」(=ローカルの Claude Code セッション)にしていました。今回はそれを踏襲しつつ、比較を機械的に回すために回答役をサブエージェントにしています。
土台の2つのラッパは、検証②で使った2つの MCP サーバに対応させています。pgtool.sh は任意の read SQL を appdb に実行するもので、postgres-mcp の run_query に相当します。pi.sh は aws pi ... を実行するもので、aws-api-mcp の call_aws に相当します3。回答役にはこの2つを等しく渡し、どちらをどう使うか(pg_stat_statements で聞くか、Database Insights で聞くか)は回答役の判断に任せました。
2.2. 「Skill の自動起動」はどう扱ったか(正直な断り)
今回の検証で1つ分かったことがあります。Claude Code のサブエージェントは、プロジェクトの .claude/skills/ に置いた Skill を自動では受け取りません。公式ドキュメントの「サブエージェントが継承するもの」に、プリロードされる Skill の内容は(明示指定しない限り)継承しない、と明記されています4。一方で MCP サーバはツールとして継承されますが、.mcp.json の追加はセッションの再起動が必要です。
そのため今回は、Skill 本文(SKILL.md の中身)を回答役のプロンプトにそのまま渡すことで「Skill が起動して本文がコンテキストに載った状態」を再現しました。ランブック無しは何も渡さない、簡易は簡易版本文、詳細は詳細版本文、という切り分けです。今回の主眼は、Skill の中身(ランブック)が答えを変えるかどうかで、description からの自動起動の仕組みそのものではありません。起動した結果の状態(本文がコンテキストに載った状態)を再現できれば、この主眼を測るには十分です。そのため「description からの自動起動そのもの」は測定対象から外し、公式仕様と上記のサブエージェントの制約として扱います。
ここは「サーバ(Skill の仕組み)の機能」と「クライアント(回答役)の挙動」を混同しないための区別でもあります。
なお、この「本文をそのまま渡す方法」が実際の起動と同じ挙動になることは、別途1回、実クライアントで裏を取りました。詳細版を個人フォルダ(~/.claude/skills/)に本物の Skill として置き、実 MCP(postgres-mcp)を接続した状態で「Aurora でいま重い SQL を3件教えて」と聞くと、description から Skill が起動し、応答は渡したときと同じくランブックの手順・判定基準に沿いました(図1)。以降の3条件比較は、この起動を本文をそのまま渡す形で再現したものです。
図1: 実クライアント(postgres-mcp 接続)で診断ランブック Skill が起動した場面。冒頭で「専用のランブック(手順書)に沿って診断します」と述べ、pg_stat_statements から Top3 を取得し、上位3件が総実行時間の92.8 %を占めることまで判定している。EXPLAIN ANALYZE は readonly 接続のため不可、とも明示している。
3. ランブックの Skill 化
3.1. 作業メモが Skill になる
Agent Skill の本体は SKILL.md という Markdown ファイルです。先頭に name と description を書き、本文に手順を書きます。name は64文字以内・小文字英数字とハイフンのみ、description は1024文字以内で「何をする・いつ使う」を書く、という制約があります2。
今回は検証②の作業メモにあった内容を、そのまま診断ランブックの本文にしました。「pg_stat_activity で実行中を見て、無ければ pg_stat_statements の累積へ」「Database Insights は負荷が走った時間帯を含める」「pg_stat_statements_reset() は rds_superuser では実行できない」といった、②で実際につまずいて得た知識です。
簡易版と詳細版で name は同じ(aurora-top-sql-runbook)にし、description のうち「いつ使うか」の部分(Aurora/PostgreSQL で今・直近で重い SQL を尋ねられたら)も共通にしました。変えたのは「何をするか」=本文の厚みだけです。
3.2. 簡易版(取得の導線だけ)
簡易版は「どのビュー・指標を、どの順で見るか」の取得手順だけを書き、判定基準や改善策は入れていません。骨子は次のとおりです。
- 「いま重い」を3つに分解する(実行中=pg_stat_activity / 累積=pg_stat_statements / 時系列=Database Insights)
- 経路1:
pg_stat_activityで実行中を見て、無ければpg_stat_statementsを total_exec_time 降順 - 経路2: Database Insights の
db.load.avg曲線で負荷の時間帯を特定し、その時間帯で Top SQL - T2・T3: 上位クエリの EXPLAIN(実行はせず計画のみ)→ pg_indexes で索引・定義を確認
3.3. 詳細版(取得+判定基準+改善策)
詳細版は、簡易版に「正常/異常の判定基準」「推奨アクションの対応表」「既知の注意点」を足したものです。②の作業メモの判断知識がここに入ります。抜粋します。
判定基準の例:
- 偏りの判定: 上位3件が総実行時間の大半(例: 90 %以上)を占めるなら、負荷は少数のクエリに集中している
- 累積(pg_stat_statements の総実行時間)と AAS(Database Insights の db.load.avg)は別の物差しである点を回答で明示する
- pg_stat_statements は累積スナップショット。2回引いて calls が不変なら新規実行は発生していない
改善策の対応表(観測→改善策):
| 観測 | 改善策 |
|---|---|
| フィルタ/結合列に索引が無く Seq Scan | カバリングインデックス(INCLUDE)や複合索引 |
| 全件集計・DISTINCT が要件(索引で消せない) | マテリアライズドビューで集計の事前計算 |
| read が多く shared_hit が少ない(shared_buffers < テーブルサイズ) | Serverless v2 の Min ACU 引き上げ/shared_buffers 見直し |
| dead tuple 率が高い・統計が古い | ANALYZE/autovacuum 設定の見直し |
既知の注意点の例:
-
pg_stat_statements_reset()は rds_superuser では permission denied - Database Insights の時間範囲が負荷時刻からズレると Keys が空になる
- Database Insights には
END(トランザクション終端)がノイズとして上位に出る(pg_stat_statements には出ない) -
round(double precision, integer)は存在しないのでround(total_exec_time::numeric, 1)とキャストする
4. 3条件の会話
同じ3ターンを、無/簡易/詳細それぞれで流しました。T1「いま重い SQL を3件教えて」、T2「いちばん重い SQL の実行計画を見せて」、T3「この SQL のチューニング案を出して」です。ターンごとに1問ずつ渡し、回答役が先の質問を先読みしないようにしています。
負荷は3条件とも同じで、pg_stat_statements の Top3 は毎回 q2(JOIN+集計)> q1(バケット集計)> q3(DISTINCT)の順、上位3件で累積の約94 %でした。Database Insights でも同じ順です。
4.1. T1: いま重い SQL を3件
3条件とも、pg_stat_activity に実行中のクエリが無い(負荷は少し前に終わっている)ことを確認し、pg_stat_statements の累積へ切り替えて、同じ Top3 に到達しました。答えの中身は3条件で同じで、差が出たのは取得の広さと解釈の深さです。
| 条件 | 取得の経路 | 解釈 |
|---|---|---|
| 無 | pg_stat_activity → pgss → Database Insights でも突き合わせ | 上位3件で約94 %と言及 |
| 簡易 | pg_stat_activity → pgss で停止(DI 未使用) | Top3 を提示(判定は薄い) |
| 詳細 | pg_stat_activity → pgss → Database Insights で突き合わせ | 93.7 %集中・pgss と DI が同順なら CPU バウンド・累積 vs AAS の物差しの違い・END ノイズ除外を明示 |
興味深いのは、簡易ランブックを渡した条件(簡易)だけが Database Insights を使わなかったことです。簡易版の「実行中→無ければ累積」という線形の導線に忠実に従い、経路1で答えが出た時点で「十分」と判断して止まりました。ランブック無しの条件(無)は、指示されなくても Database Insights でも裏取りしていました。
詳細条件は、ランブックの判定基準を明示的に当てています。上位3件が総実行時間の93.7 %を占めることを実際に計算し、pg_stat_statements と Database Insights が同順であることから「CPU バウンド」と判定し、累積(ミリ秒)と AAS(同時アクティブセッション数)が別の物差しである点にも触れました。Database Insights の4位に出た END を、詳細版の「END ノイズ」の記述どおり解釈から除外もしています。
4.2. T2: 実行計画(ここで差がはっきり出た)
T2 で3条件の差が最も鮮明になりました。
| 条件 | 取得方法 | 読み取れた内容 |
|---|---|---|
| 無 |
EXPLAIN (ANALYZE, BUFFERS) を実行 |
実測 I/O(cold cache で約92 MB を read、shared read 約6.7秒相当)まで特定 |
| 簡易 | 素の EXPLAIN (ANALYZE なし) |
推定コストのみ。実測 I/O は取れず(回答役自身が「ANALYZE を避けたトレードオフ」と明記) |
| 詳細 |
EXPLAIN (ANALYZE, BUFFERS) を実行 |
実測 I/O +「hit vs read=キャッシュ効率」の観点で明示 |
ランブック無しの条件(無)は、実行計画を求められて自発的に EXPLAIN ANALYZE を選び、pgbench_accounts のフルスキャンと、キャッシュに載りきらないための物理 read(cold cache)が重さの正体だと突き止めました。
一方、簡易ランブックを渡した条件(簡易)は、簡易版の「上位クエリの EXPLAIN(実行はせず計画のみ)」という一文に忠実に従い、ANALYZE を付けない素の EXPLAIN を実行しました。その結果、推定コストからフルスキャンがボトルネックだとは読めたものの、実測の I/O は取れませんでした。回答役自身が「EXPLAIN 単体だと実測の buffers/actual time は分からない」と書いています。簡易ランブックの一文が、ランブック無しなら取れていた情報を取り損なわせたわけです。
詳細ランブックを渡した条件(詳細)は、詳細版に「EXPLAIN ANALYZE は readonly で拒否されることがある」という注意点と「shared_hit vs read 比=キャッシュ効率」という観点の両方が書いてあります。回答役は拒否に備えて素の EXPLAIN も用意したうえで EXPLAIN ANALYZE を先に試しました。通ったので実測 I/O を取り、read が hit を上回っている=キャッシュ効率が低いと解釈しています。
なお今回の土台(psql 直結)には readonly のブロックがないため、3条件とも EXPLAIN ANALYZE 自体は実行できる環境でした。差を生んだのは環境の制約ではなく、渡したランブックの記述です。
別途、実 MCP(postgres-mcp・readonly)で詳細版を起動させたとき(図1)は、EXPLAIN ANALYZE が readonly でブロックされました。詳細版はこの注意点を書いてあるので、素の EXPLAIN に切り替える想定です。今回の psql 土台では ANALYZE が通ってしまいましたが、検証②と同じく実 MCP 経由なら readonly が働くことは、この起動の1枚で裏取りできました。readonly が守るのはツール経由の操作までで、その外側(IAM 権限や別経路の psql)は別の話、という②の整理ともつながります。
4.3. T3: チューニング案
T3 は、3条件とも高い水準の案が出て、中身はほぼ同じに揃いました。
| 条件 | 出した改善策(優先順) |
|---|---|
| 無 | カバリングインデックス/冗長 JOIN 削除/マテリアライズドビュー/キャッシュ常駐。「work_mem は今回のボトルネックでないので触らない」と除外も明示 |
| 簡易 | カバリングインデックス/冗長 JOIN 削除/マテリアライズドビュー/並列度(「並列度は I/O 総量を減らさない」と補足) |
| 詳細 | カバリングインデックス/Min ACU・shared_buffers/マテリアライズドビュー/冗長 JOIN 削除。「dead tuple は0.6 %で健全なので VACUUM は不要」と除外を明示 |
3条件とも第一手は「(bid, abalance) のカバリングインデックスで index-only scan 化」で一致しました。全条件が pg_stats で bid の n_distinct=15・correlation=1、pg_settings で shared_buffers 128 MB < テーブル193 MB、を確認したうえで根拠つきの案を出しています。
差は中身ではなく進め方に出ました。詳細条件は、ランブックの「観測→改善策」対応表をチェックリストのように使い、4行それぞれを観測値に突き合わせて採否を決めました(該当しない「dead tuple → ANALYZE」の行は、実測の dead tuple 率0.6 %を根拠に明示的に外す)。詳細ランブックの効果は「新しい改善策が出る」ことではなく、「同じ改善策が、根拠を明示した確認しやすい形で出る」ことでした。
5. 差分を「取得 / 解釈 / 改善策」に分類する
検証②で使った枠組みでは、データ取得は道具(ツール)の担当、解釈・判定と改善策は知識の担当、と整理していました。今回の差分をこの3段に割り振ると次のようになります。
| ターン | 観点 | 無 → 簡易 の変化 | 簡易 → 詳細 の変化 |
|---|---|---|---|
| T1 | 取得 | Database Insights の突き合わせを省いた(取得が減る) | Database Insights の突き合わせが戻る |
| T1 | 解釈 | ほぼ差なし | 90 %集中・CPU バウンド・物差しの違い・END 除外を明示 |
| T2 | 取得/解釈 | 「計画のみ」に従い実測 I/O を取り損ねた | ANALYZE を選び直し、キャッシュ効率で解釈 |
| T3 | 改善策 | ほぼ差なし(中身は同等) | 対応表のチェックリスト運用で確認しやすくなる |
こう見ると、当初の仮説「Skill が差を生むのは解釈・改善策で、取得には差が出ない」は、次のように補正されます。
- 解釈: 詳細ランブックは解釈をはっきり改善した(判定基準・注意点の明示適用)。仮説は支持
- 改善策: 改善策の中身は3条件で揃った。詳細版の寄与は「新しい答え」でなく「一貫した・確認しやすい答え」。仮説は部分支持
- 取得: 「差が出ない」は不正確だった。手順を細かく決めた簡易ランブックは取得を減らしうる(DI 省略・実測 I/O 取り損ね)。詳細版はそれを回避した。仮説は部分否定+補正
6. 考察
「Skill を持たせるか」より「ランブックをどう設計するか」で差が出ました。簡易ランブックの「実行計画は EXPLAIN で(実行せず計画のみ)」という一文は、取得手順を明確にする代わりに、ランブック無しなら取れていた実測 I/O を取り損なわせました(4.2 章)。手順を細かく決めすぎると、モデルが本来やる探索を減らすことがあります。
改善策(T3)は土台のモデルが元々かなり答えられました。ランブック無しでも、shared_buffers とテーブルサイズの大小を確認し、カバリングインデックス・マテリアライズドビュー・キャッシュ常駐を根拠つきで並べ、「work_mem は触らない」と除外まで示しました。詳細ランブックが足したのは新しい改善策ではなく、観測と改善策を突き合わせて採否を明示する一貫性・確認しやすさでした。ここは、Skill の価値を「賢くする」ではなく「毎回同じ手順で説明できるようにする」と捉えるほうが実態に合います。
最も差が出たのは解釈(T1・T2)でした。上位3件が総実行時間の何 %か、累積と AAS は別の物差しである、Database Insights の END はノイズである、といった②で得た判断知識を、詳細ランブックは明示的に当てさせました。これは道具(pgss や DI を叩くこと)ではなく知識の担当で、②の作業メモがそのまま③の Skill として噛み合った部分です。
T3 で改善策が揃ったのは、今回の対象が「全件集計を毎回フルスキャンする」という原因が素直なワークロードだったことも大きいと考えられます。原因の切り分けが難しい(待機イベントが絡む・複数要因が重なる)ケースほど、詳細ランブックの判定基準が差を生む余地は広がると考えられますが、これは今回の実測の範囲外です。
なお、回答役がツールを自発的に選んだり(pg_stat_statements か Database Insights か)、実行計画のために別コマンドへ回ったりするのは、クライアント(モデル)側の判断であって Skill の機能ではありません。検証②では「MCP を OFF にしても、IAM と Bash があれば psql で接続する手段を自作できる=到達可否を決めるのは MCP でなく IAM」を確認しました。今回も、Skill は答えの解釈と説明の質を変えましたが、どのデータに到達できるか自体は土台(psql/AWS CLI と IAM)が決めています。Skill が変えるのは「取れた数字をどう読み、何を薦めるか」の部分です。
7. まとめ
Aurora の診断ランブックを Claude の Skill にして、「いま重い SQL」への答えの変化を、無/簡易/詳細の3条件で実測しました。答えの中身(重い SQL 3件・実行計画・チューニング案)は3条件でほぼ揃い、差は取得の広さと解釈の深さに出ました。詳細ランブックは解釈を体系化する一方、手順を細かく決めた簡易版は取得をかえって減らすこともありました。改善策は3条件で中身が揃い、詳細ランブックの寄与は新しい答えより一貫性・確認しやすさでした。
Skill に何を持たせるかの指針としては、取得の手順を細かく規範化しすぎず(モデルの探索を残す)、判定基準・既知の注意点・観測から改善策への対応表という「判断の知識」を持たせるのが噛み合う、というのが今回の実測から言えることです。②で実際につまずいて得た作業メモが、そのまま③の Skill の中身になりました。
参考
-
Amazon の Performance Insights は 2026-07 に CloudWatch Database Insights へ統合されました(Performance Insights のコンソールは 2026-07-31 に終了)。API(
aws pi ...)とメトリクス(db.load.avg等)は名称変更なく存続します。本稿では製品名を Database Insights と表記し、API・メトリクスは実名のまま示します。 ↩ -
Anthropic, "Agent Skills overview"(SKILL.md の構造・progressive disclosure). https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview ↩ ↩2
-
この aws-api-mcp-server(awslabs)は本検証の完了後、2026-07-15 付で非推奨になりました(後継はマネージドリモートの AWS MCP Server。AWS CLI v1 のメンテナンスモード入りが理由で、削除予定は 2027-07-15)。今回の土台は WSL の AWS CLI ラッパで、非推奨になったサーバ自体には依存していません。 ↩
-
Anthropic, "Subagents"(What subagents inherit). https://code.claude.com/docs/en/agent-sdk/subagents ↩
