Slide 1

Slide 1 text

LLM 時代のパフォーマンスチューニング MongoDB 運用で試したコンテキスト活用の工夫 第35 回 中国地方DB 勉強会 in 岡山 ishikawa-pro 1

Slide 2

Slide 2 text

自己紹介 名前: 石川 諒( いしかわ あきら) X: ishikawa__pro 出身: 島根県 住んだことがある地域: 広島県福山市, 岡山県倉敷市 仕事: 主にサーバーサイドエンジニア( 現在は有休消化中) 技術: TypeScript/Node.js( サーバーサイド), MongoDB, Platform Engineering, AI エージェント活用 2

Slide 3

Slide 3 text

宣伝 3

Slide 4

Slide 4 text

今日話すこと AI コーディングエージェントを活用して、サービスのパフォーマンス ( 主にDB を) 改善をしていくノウハウについて共有します 事前に題材となる簡単なWeb サービスを用意したので、それをベース にお話しします ※ 今回は MongoDB を題材に話しますが、RDB 利用者でも使えるノ ウハウだと思います 4

Slide 5

Slide 5 text

MongoDB 超入門 5

Slide 6

Slide 6 text

MongoDB の特徴 Document 指向DB NoSQL データベースに分類 スキーマレス (Application 側でODM を使ってスキーマ定義すること が多い) BSON(Binary JSON): JSON ライクなデータ形式で保存される 水平スケーリング(Sharding): データを「シャードキー」という基準 で分割し、複数のサーバーに保存できる ドキュメント単位の原子性を保証 一応マルチドキュメントトランザクションもある 6

Slide 7

Slide 7 text

MongoDB データ設計 非正規化が基本 Embed( 埋め込み) とReference( 参照) を使い分ける Embed Document 内にデータを埋め込む 一緒に読み込むことが多いデータの場合などに利用する Referene 別 Collection の _id を保持して参照する データが数万件などの大きくなる可能性がある場合や、独立して管理したい場合に利用 する 1 ドキュメントのサイズ上限は 16MB 7

Slide 8

Slide 8 text

{ "_id": { "$oid": "66e2b8f7a9b1c2d304000010" }, "name": " ベーシックT シャツ", "sku": "TSHIRT-BASIC-001", "category_id": { "$oid": "66e2c111a9b1c2d304100001" }, // Reference: カテゴリ "price": 2000, "currency": "JPY", "status": "active", // Embed: よく一緒に使う情報 "images": [ { "url": "https://cdn.example.com/tshirt/front.jpg", "alt": " 正面" }, { "url": "https://cdn.example.com/tshirt/back.jpg", "alt": " 背面" } ], "description": " シンプルで着回しやすい定番T シャツ。" } 8

Slide 9

Slide 9 text

ストレージエンジン WiredTiger というストレージエンジンがデフォルト ドキュメント単位のロックや MVCC(Multi-Version Concurrency Control) によって、高い並行性を持つのが特徴 9

Slide 10

Slide 10 text

インデックス RDB と大体一緒 インデックスは b-tree で管理 単一フィールドインデックス ユニークキー制約 複合インデックス Multikey Index ( 配列を含むフィールドをインデックス化) その他、TTL Index など特徴的な Index も色々ある( 割愛) 10

Slide 11

Slide 11 text

MongoDB の用語整理 RDB と MongoDB の用語マッピング RDB MongoDB Table Collection Row( 行) Document Column Field Object-Relational Mapping(ORM) Object-Document Mapping(ODM) 11

Slide 12

Slide 12 text

AI エージェント超入門 12

Slide 13

Slide 13 text

AI エージェントとは 人間の指示や状況に応じて自律的にタスクを実行 するAI プログラム 仕組み 大きく3 つの要素で成り立っている 1. 理解する: 人間の指示や状況を自然言語で理解 2. 計画する: タスクを分解し、どの順序で実行する かを決定 3. 実行する: 計画に沿ってタスクを実行 ChatGPT や Claude.ai のようなチャットを介して 会話するだけのツールは、AI エージェントではな い 13

Slide 14

Slide 14 text

AI コーディングエージェント とは ソフトウェア開発に特化した AI エージェン ト ゴール(例:バグ修正・新機能追加・PR 作 成)を与えると、ゴールを達成するまで自律 的に作業をする 理解・計画のフェーズでは、コードベースを ベクトル検索や grep, ripgrep などのテキス トベースの検索を利用しながら理解し、計画 を立てる 14

Slide 15

Slide 15 text

代表的なAI コーディングエージェント IDE 系 Cursor の Agent Mode Windsurf の Cascade GitHub Copilot Agent Mode CLI 系 Claude Code Gemini CLI Codex (CLI 版) Web サービスなどを経由して background で動く系 Devin Codex (ChatGPT のアプリ or Web から指示を出す) Cursor の Background Agent 他にもいっぱいある 15

Slide 16

Slide 16 text

AI コーディングエージェントを利用して アプリケーションのパフォーマンス改善をする 16

Slide 17

Slide 17 text

今回の題材について 17

Slide 18

Slide 18 text

題材の構成 サービス概要 EC サービスの商品一覧と詳細ページのみ アプリケーション構成 サーバー: Node.js + Express.js DB: MongoDB ODM: Mongoose サーバー: ローカルの docker 上で起動 VibeCoding でフロントエンドも実装しました ( が今回は使いません笑) 18

Slide 19

Slide 19 text

システムアーキテクチャ 19

Slide 20

Slide 20 text

データベース設計 Product コレクション title: 商品名 description: 商品説明 category: カテゴリ名 price: 価格 stock: 在庫数 tags: タグ配列 createdAt: データの作成日 pupularity: 人気指標 20

Slide 21

Slide 21 text

サンプルデータ { "title": "Wireless Bluetooth Headphones", "description": " ノイズキャンセリング対応のワイヤレスヘッドホン。", "category": "electronics", "price": 12980, "stock": 57, "tags": ["audio", "bluetooth", "headphones"], "createdAt": "2025-09-11T00:00:00.000Z", "popularity": 12 } 21

Slide 22

Slide 22 text

API GET /products Product Collection のデータを20 件返す GET /products/:id 指定された id の Product を一件取得して返す 22

Slide 23

Slide 23 text

テーマ EC サイトの商品一覧と詳細ページで、意図的に slow query が発生す る実装になっている AI コーディングエージェントに適切な情報を渡して、 AI にパフォーマンス改善をやらせる 23

Slide 24

Slide 24 text

パフォーマンスの計測について 24

Slide 25

Slide 25 text

パフォーマンス計測方法 スクリプトで事前に 10 万件のデータを用意し、k6 という負荷試験ツ ールを使って、API を経由してDB に負荷をかる AI が加えた変更の前後で、どのくらいパフォーマンスが変わったを比 較する サーバーのアクセスログと、 MongoDB で 100ms 以上かかる query を 保存する( 計測とAI に渡すため) 25

Slide 26

Slide 26 text

26

Slide 27

Slide 27 text

計測のシナリオ 商品一覧と商品詳細へのアクセスを混ぜて、負荷をかける 負荷のかけ方 同時アクセス数は、最初は5 から始める 3 分かけて同時アクセス数を25 まで増やす 25 の状態を2 分間維持 終了時は約30 秒かけてゆっくり減す 27

Slide 28

Slide 28 text

計測のシナリオ リクエストの内訳(1 回ごとの動き) 7 割の確率で「商品一覧」を叩く。3 割は「商品詳細」を叩く。 一覧のときは毎回クエリ条件を変更: 並び順は「人気度(popularity) 」40% / 「価格(price) 」30% / 「作成日 (createdAt) 」30% 昇順・降順は半々 ページは1 〜5 のどれか、件数は12/24/48 のどれか ときどきキーワードやカテゴリ、最小/ 最大価格を付ける 詳細のときは、最初に集めたID からランダムに1 つ選んで開く 各リクエストのあいだに0.1 〜0.3 秒の待ち時間を入れる 28

Slide 29

Slide 29 text

29

Slide 30

Slide 30 text

改善前の負荷試験結果 エンドポイントごとの平均レイテンシー 30

Slide 31

Slide 31 text

改善前の負荷試験結果 エンドポイントごとのp95 レイテンシー 31

Slide 32

Slide 32 text

改善前の負荷試験結果 DB の p95 latency とカウントの散布図 32

Slide 33

Slide 33 text

改善アプローチ 今回は Codex (OpenAI のコーディングエージェント) のWeb 版を利用 1. 負荷試験で発生した slow query のログを Codex で集計 2. 集計結果をもとに適切な index を提案させる 3. 提案に沿って index を追加して Pull Request を作成 (mongoose の model に index を追加) 4. 再度負荷試験を実施 33

Slide 34

Slide 34 text

ログの収集 100ms 以上の query を slow query として記録して、ファイルに書き出 す Codex に分析させるためにログファイルをコミットしておく ※ MongoDB の slow query log の設定をすることで、ログ出力させる こともできるが、今回はサーバーサイドで middleware を実装して、 ファイルに書き出すようにしました 34

Slide 35

Slide 35 text

下記のようなjson を1 行化して、1 ファイルに追記していく { "ts": "2025-09-12T15:48:45.906Z", "layer": "mongoose", "op": "countDocuments", "model": "Product", "collection": "products", "ms": 100, "filter": { "$or": [ { "title": {} }, { "description": {} } ] }, "options": {} } 35

Slide 36

Slide 36 text

ログの収集 Codex に jq を使って、 slow query のログを集計させる 36

Slide 37

Slide 37 text

query の数値などを ? に置き換えて、グルーピングする jq のスクリ プトも作成してくれた 37

Slide 38

Slide 38 text

下記のような csv ファイルが作成される query をグルーピング化して、呼び出し回数と p95 を集計したファイ ル "op","model","collection","filter","options","n","p95_ms" "countDocuments","Product","products","{}","{}",189,160 "find","Product","products","{}","{""sort"":{""createdAt"":""?""},""skip"":""?"",""limit"":""?""}",102,169 "find","Product","products","{}","{""sort"":{""popularity"":""?""},""skip"":""?"",""limit"":""?""}",126,152 ... 38

Slide 39

Slide 39 text

ログの収集 こちらも Context として利用するために、リポジトリにコミットする 39

Slide 40

Slide 40 text

ログの解析 集計したログを利用して、パフォーマンス改善のための index 追加の 提案をさせる 40

Slide 41

Slide 41 text

ログの解析 発生回数とp95 latency から優先度の高い slow query を算出 41

Slide 42

Slide 42 text

ログの解析 推奨するタスクを提案してくる 42

Slide 43

Slide 43 text

ログの解析 提案してきたタスク title と description の全文検索 index の追加 一番 slow query の回数とlatency が悪かった popularity と createdAt に index を追加 filter なしで、 popularity, price, createdAt のソートが多いため price 関連の index 追加 price + popularity, price + createdAt の2 つの 複合index を提案 43

Slide 44

Slide 44 text

ログの解析 提案してきたタスク title と description の全文検索 index の追加 popularity と createdAt に index を追加 price 関連の index 追加 ( 却下) まずは price も 単一のindex を貼って判断 44

Slide 45

Slide 45 text

title と description の全文検索 index の追加 45

Slide 46

Slide 46 text

title と description の全文検索 index の追加 46

Slide 47

Slide 47 text

popularity と createdAt と price の index の追 加 47

Slide 48

Slide 48 text

popularity と createdAt と price の index の追 加 48

Slide 49

Slide 49 text

4 つの index を追加(_id, cateogry 以外) 49

Slide 50

Slide 50 text

再度負荷試験 50

Slide 51

Slide 51 text

改善後 DB find の slow query はなくなり、 countDocuments だけになった 51

Slide 52

Slide 52 text

API の平均レイテンシーの比較 大幅に改善 52

Slide 53

Slide 53 text

API のp95 レイテンシーの比較 一件取得は大幅に改善 一覧取得は、おそらくcountDocuments がまだブロックしている 53

Slide 54

Slide 54 text

まとめ 54

Slide 55

Slide 55 text

まとめ AI コーディングエージェントは機能開発だけでなく、アプリケーショ ンのパフォーマンス改善にも使える ただしコードベースだけでは、具体的にどのようなリクエストがどの くらい発行されているかなど、どう使われているのかという情報が足 りない コードベース以外に slow query log やメトリクスなどが必要 55

Slide 56

Slide 56 text

まとめ パフォーマンス改善にあると良い Context 具体的な query ( 値などはマスクされてても良い) アクセスログ ( コード上のどのエンドポイントなのかを特定するため) 発生頻度や latency などのmetrics(AI に分析や優先度などを考えさせるた め) エージェントが触れる環境 ローカルに DB を立てるなどして、エージェントが触れる環境を提供す ると、より自律的かつ精度よく作業するようになる( 本番環境はダメ) 56

Slide 57

Slide 57 text

まとめ 今回は MongoDB を題材とし、エージェントに Codex を利用しました が、他の DB や AI エージェントでも活用できると思います( 自分も実務 では Codex ではなく Devin にやらせていました) 個人的なおすすめは、 Devin や Codex などのクラウド上で Background で動作してくれるエージェント エージェントに Cotext を渡して改善の PR を作成させ、自分の手が空 いてる時に確認・検証をすれば良いだけになるため楽 57