メインコンテンツへ移動

MongoDB スロークエリ分析

MongoDB profiler に基づいてスロークエリを自動識別し、インデックス最適化を提案します。「リソース監視 → MongoDB」のスロークエリタブから利用できます。

前提条件
  • 診断対象の MongoDB をデータソースページで追加して有効にし、用途のスロークエリ診断を選択してください。
  • 診断を有効にした複数のインスタンス(シャードクラスターの複数シャードなど)は自動的に集約分析され、追加設定は不要です。

仕組み​

  1. profiler の有効化:対象データベースで profiling が無効な場合、運用プラットフォームは db.runCommand({profile:1, slowms:100}) を自動実行して有効にします(監視対象データベースに対する唯一の設定書き込みであり、インデックスの作成や業務データの書き込みは行いません)。監視アカウントの権限が不足している場合はログに Permission denied が出力されるため、後述の手順で手動有効化してください。
  2. 収集:10 分ごとに MongoDB の system.profile から取得し、直近 120 分のレコードのみを分析します。1 回の取得上限は 2000 件です。
  3. 抽出:スキャンしたドキュメント数が 100000 以上のレコードのみを残します。実行時間が長くてもスキャン数が少ないクエリは記録されません。
  4. グループ化:query shape(具体的なパラメーター値を無視したクエリテンプレート)で集約し、同一フィンガープリントの累計出現回数が 50 回以上の場合に保存します。グループごとに累計回数、平均/最大実行時間、スキャン数と返却ドキュメント数、代表例を表示します。
  5. 保存:結果は運用プラットフォーム専用の ops-mongo にのみ書き込み、7 日間保持します。
  6. インデックス提案:クエリのフィールドの組み合わせと既存インデックスに基づき、作成可能な複合インデックスを提案します。ワンクリック作成にも対応します(バックエンドで createIndex を呼び出します。これは監視対象データベースに書き込む唯一の操作であり、ユーザーの明示的なクリックが必要です)。
スロークエリを取得できない場合は、まず次の 4 条件を確認

「遅い」だけでは記録されません。記録条件は**「大量スキャン + 高頻度実行」**であり、次の 4 条件をすべて満たす必要があります:

条件デフォルト値調整可能な環境変数
実行時間> 100 msENV_GATEWAY_PROFILE_SLOW_MS
スキャンしたドキュメント数≥ 100000ENV_GATEWAY_DOCS_EXAMINED
同一フィンガープリントの出現回数≥ 50 回(直近 120 分以内)—
収集周期10 分ごとENV_GATEWAY_CAPTURE_INTERVAL_MS

20 秒かかるクエリを 1 回実行するだけでは記録されません。スキャン数が 10 万未満、出現回数も 50 回未満である可能性があります。再現には通常 30 万行以上のテーブルを用意し、バッチ処理でフルテーブルスキャンに相当するクエリを 50 回以上実行します。

実行後は次の収集周期まで待つ必要があります。テスト環境で再現条件を緩める場合は、上表の 2 つの閾値を下げてください。

トラブルシューティング:画面にデータが表示されない​

次の順で確認します:

  1. profiling が有効か:対象データベースで db.getProfilingStatus() を実行し、was が 1、slowms が 100 であることを確認します。0 のままなら運用プラットフォームによる有効化に失敗しており、通常は監視アカウントの権限不足が原因です。
  2. system.profile にレコードがあるか:
    db.system.profile.find({ docsExamined: { $gte: 100000 } }).sort({ ts: -1 }).limit(5)
    空の場合は、作成したデータがスキャン数の閾値に達していません。運用プラットフォームの問題ではありません。
  3. system.profile にレコードがあるのに画面が空の場合:通常は同一フィンガープリントの出現回数が 50 回未満か、10 分の収集周期にまだ達していません。

profiler を手動で有効化(アカウントの権限不足時のみ)​

通常は運用プラットフォームが自動的に有効化します。ログに Permission denied が出る場合は、各監視対象データベースで手動有効化します(slowms はスロークエリの閾値で、本番環境では 100~500ms を推奨します):

use mdwsrows; db.setProfilingLevel(1, { slowms: 100 })
use mdservicedata; db.setProfilingLevel(1, { slowms: 100 })
use mdworksheet; db.setProfilingLevel(1, { slowms: 100 })
use mdworkflow; db.setProfilingLevel(1, { slowms: 100 })

注意事項​

  • profiler には約 1~3% のオーバーヘッドがあります。本番環境では slowms の閾値以上のみを収集し、level=2(全件収集)は使用しないでください。
  • system.profile は capped collection(デフォルト 1MB)であり、QPS が高いとすぐに上書きされます。保持期間を延ばす場合は容量を増やせます:
    db.setProfilingLevel(0)
    db.system.profile.drop()
    db.createCollection("system.profile", { capped: true, size: 100000000 }) // 100MB
  • ワンクリックでインデックスを作成する前に書き込みへの影響を評価し、必要に応じて低負荷の時間帯に実行してください。