こんにちは、プロダクト開発部の中田です。
現在はテーブル解体チームに所属し、メインプロダクトのレガシーシステムと向き合う日々です。
本記事では、その中で取り組んでいるDB負荷調査について、Claude Code で調査を自動化しようとした過程と、そこから得た気づきをご紹介します。
はじめに
テーブル解体チームは、弊社内で「汎用テーブル」と呼ばれている大きなテーブル群を、用途に応じた適切な形にリファクタリングしていくことをメインミッションとしています。
この「汎用テーブル」については、以下の記事で説明されているので、興味のある方はそちらもご覧ください。
テーブル解体の目的は、テーブル構造などに起因するDB負荷高騰を抑え、サービスの安定稼働を維持することです。
弊社のメインプロダクトはモノリスとして稼働しており、紐づくDBも単一の Amazon Aurora MySQL クラスターで運用されているため、DBの安定稼働はサービスの安定稼働に直結します。
その目的のもと、テーブル解体チームでは、サブミッションとして、DB負荷高騰の兆候に対する日々のモニタリングと細かな問題解決も行っています。
こうした調査と対処を繰り返していると、調査手順にもパターンが見えてきました。そこで、AIを使って調査の知見を集約しつつ作業を効率化したいと考えました。
DB負荷の典型的な調査パターン
モニタリングによる検知から原因特定と対処検討までは、次のような流れになることが多いです(事象によっては省略されるステップもあります)。
- Datadog のダッシュボードを見て、Average Active Sessions(AAS)や History List Length(HLL)の上昇のような負荷高騰の兆候を見つける
- Datadog APM や Amazon RDS Performance Insights で、該当時間帯のスロークエリを特定する
- Datadog APM のトレース、もしくはコードベースの調査から、問題のクエリを呼び出している API エンドポイントやバッチ処理を特定する
- Amazon Athena(以下、Athena)上のアクセスログやアプリケーションログから、対象の API エンドポイントやバッチ処理の呼び出し状況を確認する
- Athena 上のDBバックアップデータから、問題のクエリに関連するデータの件数やカーディナリティを確認する
- 本番DBに接続して問題のクエリの実行計画を確認する
- ここまでの情報から、負荷高騰のメカニズムを特定し、対処方法を検討する
ちなみに、対処の手段としては、以下のようなものを採ることが多いです。
- クエリの改善(where や join の条件最適化、クエリの分割や統合)
- インデックスの追加・削除
- 仕様変更(検索条件やソート条件の変更、バリデーション条件やページング機能の追加)
ただし、ものによっては、テーブル構造の見直しのような根本対処が不可欠で、時間がかかるものもあります。 そういうものは、テーブル解体のバックログに乗せて優先度を判断していくことになります。
いずれにせよ、再発防止のための迅速な調査・検討と、サービス影響を抑えるための慎重な対処が求められます。
調査結果の「正しさ」をどう確認するか
報告された調査結果は本当に正しいのか?
ところで、DB負荷の調査に限らず、設計や仕様の調査も含めて、他人や AI がまとめた調査結果が正しいかどうかを、皆さんはどのようにレビューしていますか?
設計やコードのレビューであれば、最終成果物だけを見ても、ある程度は良し悪しの判断ができます。
一方で、「調査」というものは、「そもそもわからない・知らないから調べている」ので、結論だけ見せられても、それが本当に正しいかどうかを判断するのは難しいでしょう。
そのような場合は、結果ではなくプロセスをレビューする、というやり方を採ることが多いです。 プロセスが適切であれば、結果の信用度も高いはずだ、という判断ですね。
調査プロセスのレビューポイント
「調査」を行う場合、最初に基本的な情報をざっと収集したあとは、以下の流れを繰り返すことになります。
- 仮説の設定
- 仮説を肯定/否定する事実を収集
- 収集した事実を解釈し、仮説の正否を判断 → 1に戻り次の仮説へ
そこで、プロセスをレビューする際は、各ステップに対して以下のような問いを投げかけ、論理的な妥当性を確認します。
| ステップ | レビュー時の問い |
|---|---|
| 1. 仮説の設定 | どんな解釈をもとにどんな仮説を立てたのか |
| 2. 事実を収集 | どんなデータをどんな範囲・条件・手段で検索・抽出したのか |
| 3. 解釈と判断 | どんなデータが得られて、それをもとにどう解釈したのか |
ここで重要なのは、「事実」と「解釈」をきちんと区別することです。 事実と解釈を取り違えると、誤った結論にたどり着いてしまうリスクが高くなります。
たとえば、以下の2つの報告は似ているようで違います。
- 「2026/5/1 0:00~6:00 の範囲で
batch_app_logsに◯◯ が正常終了しましたというログが出ていない」 - 「昨日は ◯◯ バッチが起動していない」
「ログが出ていない」ことは、ログ検索のコマンドやクエリとその実行結果が記録されていれば、 「このコマンドを叩けばこの結果が返る」という誰でも再現確認できる事実になります。
一方で「バッチが起動していない」というのは、ログを見た報告者の解釈なのか事実なのか区別できません。 実際には、起動したが空振りに終わった、あるいは異常終了した、などの可能性もあり、それによって問題の原因や対処が変わってきます。 もしかしたら見るべきログ自体が間違っていたのかもしれません。
AIに調査させるときの注意点
このようにプロセスをレビューするやり方は、基本的には依頼相手が人でもAIでもあまり変わりません。
ただし、特にAIは断定的な報告をすることが多く、解釈をあたかも事実かのように言い切ることがあります。 そうなると、後続プロセスがそれを前提として、ずれた方向に突き進んでしまうため、注意が必要です。
人が相手であれば、これまでの信頼と実績をもとに報告内容を信じるという選択も可能ですが、AIの場合はいまはまだ無条件に信じるのは難しいでしょう。
次節からは、ここで挙げた「事実と解釈の区別」「再現可能なプロセス」という観点を念頭に、Claude Code で実際に試したときの課題と解決策を紹介していきます。
Claude Code に調査を任せてみたが、うまくいかない
少し前に、杉山さんが新規プロダクトでのAIを使った調査の自動化について書いてくれており、 社内でも Datadog の MCP(Model Context Protocol)の利用例などをいくつか見かけるようになってきました。
そこで、私もレガシーシステム側で、Claude Code を利用した調査の自動化をやってみることにしました。
レガシーシステムゆえの複雑さ
はじめは、簡易の runbook 的な内容だけを CLAUDE.md に書いた状態で、調査指示を出してみたのですが、どうもうまく動いてくれませんでした。
調査の様子を見ていると、あちこちで引っかかって、余計なことを調べたり、勘違いをしたり、右往左往しています。
よくよく見ていると、以下のような状況が、調査の難易度を上げていることがわかりました。
- 施設向け、保護者向け、内部通信向けなど、複数種類の Amazon ECS サービスが存在し、通信経路やログ出力先が異なる
- ECS サービスごとに、Application Load Balancer(ALB)アクセスログ、Apache アクセスログ、PHP アプリケーションログ、DBアクセスログなど、複数種類のログが存在する
- それぞれのログ形式は、タイムスタンプの型・形式や UTC/JST の混在など、項目の有無や値の形式に細かい違いがある
- すべてのログ・メトリクスが Datadog に送信されているわけではない(一部のログレベルは送信対象外、DBアクセスログは更新系のみ出力、など)
- 歴史的経緯から Athena 上のログテーブルが複数存在し、特定日付の前後で出力先テーブルが切り替わっているものがある
- コードベースの規模が大きく、可読性も高いとは言えないため、どこをどう読めばいいかのコツがいる
調査の前提となるこれらの情報を、随時 CLAUDE.md に追記していたのですが、分量が増えるばかりで、AIも必ずしも全部に従ってくれず、いまいち安定しませんでした。
そもそも、これらはDB負荷調査をするうえでの本質ではないので、ここにトークンを浪費するのはもったいないです。
機密情報の扱いと承認の手間
調査の過程では、データ収集などのため、コマンド実行の承認を何度も求められます。
DBバックアップデータには個人情報も含まれていますし、アクセスログにはセッションに関する情報も含まれています。 MCP や IAM ロールの権限設定で更新処理などの危険な操作は制限されていますし、データアクセスの監査ログの仕組みなどもあるのですが、 それでもAIに自由にデータを参照・収集させるのは抵抗があります。
例えば Athena のクエリなら、調査に不要なカラムを安易に取得させないように確認してから承認します。 これも CLAUDE.md に前提として書いてはいたのですが、必ず守られる保証はないので、都度の確認を省く自信は持てませんでした。
また、メトリクス取得の AWS CLI コマンドや、取得したデータの解析に使うシェル・Python スクリプトを実行するコマンドも、毎回承認が必要になります。 数回ならともかく、コマンド実行のたびに確認するのは負担が大きく、レビューがおざなりになりがちでストレスでした。
settings.json の permissions の設定でなんとかしようと試みたのですが、コマンドの細かいパターンの組み合わせを網羅するのは難しく、挫折してしまいました。
調査プロセスの再現性
単純な調査指示を与えるだけだと、1ショットで調査を完了させて、結果だけ報告してくる傾向がありました。
これでは、前述のとおり、調査結果が正しいかを判断できません。
そこで、以下の流れをきっちり踏んで都度報告・相談してもらうように CLAUDE.md に書いたのですが、これもなかなか守ってもらえませんでした。
- 仮説の設定
- 仮説を肯定/否定する事実を収集
- 収集した事実を解釈し、仮説の正否を判断 → 1に戻り次の仮説へ
たどりついた方法
試行錯誤を経て、最終的には以下のかたちに落ち着きました。
- 調査手順を細かいステップに分割し、Claude の Skill としてまとめる
- データ収集用のスクリプトを事前に用意し、データ収集はそれらのスクリプトの実行のみ許可する
- 調査の経験知をフィードバックし、解釈や判断の精度を上げる
最初の2つは、「再現性」「レガシーゆえの複雑さ」「承認の手間」を解消するための 土台 です。 3つ目は、その土台を 実用に耐える Skill に仕上げていく過程 です。
それぞれ、次の節で詳しく見ていきます。
Skill の構成(再現性への対応)
調査フローを Skill として固定化し、各ステップで報告・相談を挟む形にすることで、AIが1ショットで結論を出してしまうのを防いでいます。 あわせて、各ステップの finding をテンプレート化することで、事実と解釈を分けて記録させやすくしています。
Skill 本体のディレクトリ構成
Skill のディレクトリ構成は以下のようになっています。
.claude/skills/db-investigate/
├── SKILL.md # コマンド本体・フロー制御
├── context.md # 環境情報・操作ルール
├── steps/
│ └── step1.md 〜 step5.md # 各ステップの手順
├── references/
│ ├── athena-tables.md # Athena テーブルの参照情報
│ ├── datadog-dbm.md # Datadog Database Monitoring の使い方
│ └── scripts.md # スクリプトの使い方
├── scripts/
│ ├── get-rds-metrics.sh
│ ├── get-pi-metrics.sh
│ ├── run-athena-query.sh
│ ├── show-table-schema.sh
│ ├── parse-metrics.sh
│ └── init-investigation.sh
└── templates/
├── investigation-template.md # 調査サマリーの雛形
└── finding-template.md # finding(個別調査)の雛形
SKILL.md と調査フロー
SKILL.md のフロントマターには以下のように書いてあり、/db-investigate 4/1 13時頃にHLL高騰しているので調査して のようなコマンドで呼び出せます。
--- name: db-investigate description: DB負荷高騰・スロークエリ事象の調査を開始する argument-hint: "[事象の説明(例: MM/DD HH時頃にHLLが高騰しているので調査して)]" allowed-tools: >- Bash(${CLAUDE_SKILL_DIR}/scripts/get-rds-metrics.sh *) ... ---
また、SKILL.md には、以下のような調査フローを定義しています。
各ステップの詳細や注意事項は、対応する stepX.md に記述してあり、ステップ実行時に参照すべきコンテキスト情報を絞り込んでいます。
### 各ステップ実行手順 各ステップの開始時に、対応する手順ファイルを Read で読み込んでから実行する: | ステップ | 手順ファイル | 内容 | |------|------------|------| | Step 1 | `.claude/skills/db-investigate/steps/step1.md` | 事象の確認 | | Step 2 | `.claude/skills/db-investigate/steps/step2.md` | 原因クエリの特定 | | Step 3 | `.claude/skills/db-investigate/steps/step3.md` | エンドポイント・呼び出し元の特定 | | Step 4 | `.claude/skills/db-investigate/steps/step4.md` | 根本原因の調査 | | Step 5 | `.claude/skills/db-investigate/steps/step5.md` | 再発防止策の検討 | ### サブタスク完了時の手順(毎回必ず実行) 1. `findings/NN-xxx/README.md` に調査結果を記録 2. `investigation.md` の該当セクションを更新: - **タイムライン**: 新たに判明した時系列情報を追加 - **事象・仮説の一覧**: 当該findingの行を追加/更新 - **因果関係の分析**: 確定事実が増えた場合に更新 3. ユーザーに報告 4. 次のアクション指示を仰ぐ(次のStepに自動で進まない)
Skill が出力する調査結果の構成
Skill が出力する調査結果は、テンプレートに沿って次のような構成になります。
db-investigation/
└── YYYYMMDD-事象概要/
├── docs/
│ └── instruction.md # 事象と調査対象時間帯の記録
├── investigation.md # 全体サマリー・タイムライン・因果関係分析
└── findings/
├── 01-事象確認/README.md
├── 02-原因クエリ特定/README.md
├── 03-呼び出し元特定/README.md
├── 04-根本原因/README.md
└── 05-再発防止/README.md
各 finding の README.md には、以下のような finding-template.md の記載に沿って書いてもらいます。
実行コマンドと実行結果が「事実」、そこから読み取れることが「解釈」にあたり、両者を分けて記録できる形です。
## 調査結果 ### 1. [調査内容の説明] **実行コマンド**: ```bash [実行したコマンド] ``` **結果**: ``` [出力結果] ``` **読み取れること**: [この結果から分かること]
investigation.md 側には、findings を踏まえたタイムライン、事象の一覧(状態を「仮説/確定/否定」で管理)、因果関係の分析、結論、対策をまとめていきます。
スクリプト化(複雑さと承認の手間への対応)
スクリプト化のねらいは以下の2つです。
- レガシーシステムゆえの複雑さをスクリプトの中に閉じ込めて、AIから見たときの認知負荷を下げること
- 毎回の承認を「許可済みスクリプトの呼び出し」にまとめて、承認の手間そのものを減らすこと
なお、Datadog については、MCP を利用していて特に詰まることもなかったので、スクリプト化は必要ありませんでした。
スクリプトの作成自体はAIが得意なので、サクッと書いてもらって、レビュー後はファイル編集を禁止し、Skill の allowed-tools に登録して運用しています。 これで、レビュー済みのスクリプトからのみデータ取得が行われるようになり、auto モード で実行しても、安心して任せられるようになりました。
具体的には、次のようなスクリプトを用意しています。
- Amazon Athena テーブルへのクエリ実行(非同期コマンドの待ち合わせ処理を含む)
- ローカル環境のDBでテーブル定義(インデックスや CREATE 文)を確認
- Amazon CloudWatch メトリクスや Amazon RDS Performance Insights のデータを一括取得・分析
- 調査結果レポートをテンプレートに沿って出力
さらに、機密情報の扱いも、データソースごとに承認レベルを分ける方針とし、スクリプト内でクエリのバリデーションを行うようにしました。
- DBバックアップ用の Athena テーブルは、
SELECTのみ許可し、クエリのレビュー(個人情報を含むカラムが入っていないか)を必須にする - ログ用の Athena テーブルは、
SELECTとSHOW CREATE TABLE程度までは許可しつつ、cookie などの一部カラムは見せない
経験知のフィードバック(判断の精度を上げる)
ここまでやると、事実と解釈を区別して仮説設定と検証を繰り返すプロセスの形式は安定するようになりました。
ただし、これはあくまで形式が整った段階で、確認すべきデータの見落とし、データの解釈の誤り、調査の方向性の間違い、などといった判断の誤りは、まだまだ起こる状態でした。
実用に耐えるレベルにはあと一歩。ここは調査の本質の部分なので、教え甲斐があるところでもあります。
そこで、実際の調査を行う中で Skill をブラッシュアップするため、AIに調査をさせると同時に、自分でも手動で並走して調査する ということをよくやっていました。
同じ事象に対する両方の結果を突き合わせると、Claude 側の指示が足りなかった箇所や、自分が暗黙のうちに行っていた判断(経験知によるショートカット)が浮かび上がってきます。
例えば、以下のようなものです。
- AIの基本動作として徹底したいルール
- 情報不足の場合に推論で判断せず、追加調査で確認する
- 見かけの仕様だけで判断せず、詳細実装を確認する
- ドメイン固有のショートカット
- 〇〇エンドポイントは恒常的にレスポンスタイムが長めなので、調査対象から除外する
- 〇〇テーブルはデータ特性的に△△のインデックスが効きづらく、怪しい候補になりやすい
こうした勘所を少しずつ Skill のステップ実行手順に反映していくことで、ひとつずつ言語化していきました。
いまでは、ステップごとの報告を確認して、「ok」「進めて」などと返したり、軽く質問やアドバイスをする程度で、ほぼ信用できる調査結果が得られるようになってきました。 そこで、メインプロダクトのリポジトリに Skill を置いてチームに共有しました。
自動化のいまとこれから
自動化のための試行錯誤をしてきて、いま思うのは、「やりすぎないこと」がむしろ重要 だということです。
いまは「半自動化」がちょうどいい
負荷高騰の兆候を検知したら、自動で調査を実施して、対処方法の提案までしてくれる、みたいな「完全自動化」までいけるとよいとは思いつつ、まだそこまでは踏み込めていません。 それでも、いまはこの形がちょうどよいと考えています。
「多分こっちだから先にこっちを調べる」のような経験や勘によるショートカットには、明確にルール化できるほどの確実性はなく、いずれにせよ事実確認は必要です。 それでも、調査効率には割と効いてきます。 完全自動化を目指そうとすると、こうしたあやふやだけど効くショートカットが扱いづらくなります。
また、ステップごとに自分が確認・判断しながら進める形のほうがレビューもしやすいです。判断の積み重ねは、そのまま自分個人の経験知にもなります。
もちろん、そういう経験知すら蓄積・整理・活用していくという方向性もあるとは思いますが、現時点ではまだコスパが悪そうな気がしています。
今後の懸念:スクリプトや Skill の負債化
今回は結局、スクリプトや Skill を作り込むことになりました。となると気になるのは今後の変化への対応です。
スクリプトや Skill が前提とするシステム構成等は今後も変化していくので、それに追従していく必要があります。 また、スクリプトが使用する CLI や MCP もバージョンアップしていきますし、AWS MCP Server など新しいツールも増えていきます。AIのモデルの進化によってベストプラクティスが変わっていく可能性もあります。
メンテナンスも AI に委ねることはできるとはいえ、その品質を保証し続けるのは難しいことも多そうです。今回話した調査タスクのように、明確な正解がないものは特にそうですね。
AIや汎用ツール(公式の MCP など)の進化に合わせて、個別の自作ツールは少しずつ 手放していく ことが大切だと感じました。 また、用途別の手順を作り込むより、システム構成をシンプルにして一次情報へのアクセス性を上げていくことも必要です。
ツールの作成が容易になったことに頼り切らず、ツールが不要な環境を整えることも、忘れずにやっていきたいです。
自動化を進めるほど、自動化の出番は減ってきた
皮肉なことに、自動化の試行錯誤を繰り返しながらいくつもの調査と対処をしてきた結果、そもそも負荷高騰の兆候自体が減ってきて、せっかく作った Skill の出番が少なくなってきました。
それ自体は喜ばしいことなのですが、なんとも言えない気持ちです。
とはいえ、今後の開発過程で、また新たなクエリが問題になってくる可能性は十分にあります。 引き続きモニタリングと迅速な調査・対処を続けながら、Skill をコンパクトに改善しつつ、最終的には Skill ごと消し去りたいものです。
そもそも、問題のあるクエリが新しく生まれにくくなる仕組みを作っていくのが、次の課題かもしれません。
おわりに
気づけば、以前 Cline について記事を書いてから、約1年が経ちました。
いまでは Claude Code を中心に使っていますが、AIの使い方としては、1年前から基本的にはあまり変わっていないかもしれません。
本記事の内容もふまえて、いま改めて感じるのは、AIは、仕事の依頼相手というより、自分の中でまだふわふわとしている思考を言語化するのを助けてくれる存在、と捉えた方がしっくりくるな、ということです。
うまく言語化さえできてしまえば、人に伝えることも、自動化や実装も、いまやそれほど難しくありません。
この記事自体も、AIに何度も推敲してもらう中で、自身の主張がだんだんと明確になってきました。 最後にこのような駄文を私が書き足したら、またAIに「文脈に合わず唐突」とか言われて削除されそうですが、そこは許してもらって、締めとしたいと思います。