MongoDBの遅いクエリを診断し解決するための実践ガイド

MongoDBにおける遅いクエリの診断と解決の技術をマスターしましょう。この実践ガイドでは、Database Profilerを使用してボトルネックを特定する方法、そして強力な`explain()`メソッドを活用して実行計画を分析する方法を教えます。ESRルールやカバリングインデックスの作成を含む必須のインデックス戦略を学び、パフォーマンスを最適化し、NoSQLデータベースが最高の効率で動作するように保証します。

MongoDBにおけるスロークエリの診断と解決:実践ガイド

MongoDBのスロークエリは、通常、データが増加したり、アクセスパターンが変化したり、インデックスがアプリケーションのデータ読み取り方法に合わなくなった場合に発生します。APIエンドポイントがタイムアウトしたり、ダッシュボードの読み込みが遅くなったり、トラフィックが正常に見えてもCPUやディスクI/Oが上昇していることに気付くかもしれません。

プロファイラを使用して遅い操作を見つけ、explain()でMongoDBがどのように実行しているかを確認し、ターゲットを絞ったインデックスを使用してMongoDBが行う作業を削減します。

クエリが遅くなる理由を理解する

インデックスを変更する前に、一般的な原因を確認してください。

  1. インデックスの欠如または非効率性: 有用なインデックスがないと、MongoDBはコレクションスキャンを実行し、すべてのドキュメントを調べる可能性があります。
  2. クエリの複雑さ: 集計ステージ、大規模なソート、またはコレクション間のルックアップを必要とする操作は、最適化されていないと本質的に遅くなる可能性があります。
  3. データ量: データセットが膨大で、フィルタリング前に数百万のドキュメントを処理する必要がある場合、インデックスが設定されたクエリでも遅くなることがあります。
  4. ハードウェアの制約: 不十分なRAM(広範なディスクスワップにつながる)や低速なディスクI/Oは、すべての操作のパフォーマンスを低下させる可能性があります。

ステップ1:プロファイリングを使用したスロークエリの特定

解決の最初のステップは特定です。MongoDBのDatabase Profilerはデータベース操作の実行時間を記録し、どのクエリが問題を引き起こしているかを正確に特定できるようにします。

プロファイラの有効化と設定

プロファイラは異なるレベルで動作します。レベル0はプロファイリングを無効にします。レベル1は設定されたしきい値より遅い操作を記録します。レベル2はすべての操作を記録します。

スロークエリを分析するには、通常、しきい値を50ミリ秒などに設定してレベル1を設定します。

// プロファイルするデータベースに切り替え
use myDatabase

// 50ミリ秒より長くかかる操作をキャプチャ
db.setProfilingLevel(1, { slowms: 50 })

プロファイラ結果の確認

記録された遅い操作はsystem.profileコレクションに保存されます。このコレクションをクエリして、最近のスロークエリを確認できます。

// 50msより長くかかる操作を検索
db.system.profile.find({ ns: "myDatabase.myCollection", millis: { $gt: 50 } }).sort({ ts: -1 }).limit(10).pretty()

レベル2は短い調査のみに使用してください。すべての操作を記録するため、本番環境のビジーなデータベースではオーバーヘッドが増加する可能性があります。

ステップ2:explain()を使用したクエリ実行の分析

スロークエリを特定したら、explain()を使用してMongoDBがどのように処理するかを確認します。

explain('executionStats')の使用

executionStats詳細レベルは、実際の実行時間やリソース使用率を含む、最も包括的な出力を提供します。

usersコレクションを対象としたこの遅いクエリを考えてみましょう。

db.users.find({ status: "active", city: "New York" }).sort({ registrationDate: -1 }).explain('executionStats')

出力の解釈

explain()出力で確認すべき主要なフィールドは次のとおりです。

フィールド 説明 遅さの指標
winningPlan stages オプティマイザによって選択された実行計画。 COLLSCAN、ブロッキングSORT、または予期しないインデックスを探します。
executionStats.nReturned 操作によって返されたドキュメントの数。 少数の結果を期待している場合に数が多いと、初期のフィルタリングが不十分であることを示します。
executionStats.totalKeysExamined チェックされたインデックスキーの数。 インデックスが効果的に使用されている場合、通常はnReturnedに近いはずです。
executionStats.totalDocsExamined ディスク/メモリから実際に取得されたドキュメントの数。 数値が高い場合、インデックスの選択性が十分でなかったことを示します。
executionStats.executionTimeMillis 実行にかかった合計時間。 これを実際のレイテンシと比較します。

危険信号:COLLSCAN

勝ちプランにCOLLSCANが含まれている場合、MongoDBはコレクションをスキャンしました。これは通常、クエリにより適したインデックスが必要であるか、述語が選択的でないか、クエリの形状がインデックスの使用を妨げていることを意味します。

ステップ3:インデックス戦略の実装

COLLSCANの解決には、通常、クエリパターンに一致するようにインデックスを作成または調整することが含まれます。

複合インデックスの作成

等価一致、範囲フィルター、ソートなど、複数のフィールドを含むクエリの場合、複合インデックスが必要になることがよくあります。一般的なESRガイドラインでは、複合インデックスのフィールドを、最初に等価述語、次にソートフィールド、最後に範囲述語の順に並べます。これはガイドラインであり、実際のクエリとデータでテストすることの代わりにはなりません。

シナリオ例: クエリ:db.orders.find({ status: "PENDING", customerId: 123 }).sort({ orderDate: -1 })

ESRに基づくと、インデックスは次の構造に従う必要があります。

  1. 等価述語(statuscustomerId
  2. ソート述語(orderDate

インデックスの作成:

db.orders.createIndex( { status: 1, customerId: 1, orderDate: -1 } )

このインデックスにより、MongoDBはステータスと顧客IDで迅速にフィルタリングし、orderDateですでにソートされた結果を効率的に取得できます。

ソート操作の処理

explain()で、多くのドキュメントが検査された後にブロッキングSORTステージが表示される場合、MongoDBはインデックスを使用してソートされた順序で結果を返すことができませんでした。

大規模なソートはメモリを消費し、サーバーバージョンとコマンドオプションによってはディスクにあふれ出る可能性があります。より良い修正方法は、通常、フィルターとソートの両方をサポートするインデックスを作成することです。

.sort()句で使用されるフィールドが、適切な複合インデックスの末尾の要素として存在することを確認してください。

ステップ4:高度な最適化テクニック

インデックスだけでは遅さが解決しない場合は、次の高度な手順を検討してください。

射影の最適化

.find()の2番目の引数である射影を使用して、アプリケーションに必要なフィールドのみを返します。これによりネットワーク転送が削減され、射影されたフィールドがインデックス内にある場合、カバードクエリが可能になります。

// _id、name、emailフィールドのみを返す
db.users.find({ city: "Boston" }, { name: 1, email: 1, _id: 1 })

カバリングインデックス

カバリングインデックスは究極のパフォーマンス目標です。これは、クエリに必要なすべてのフィールド(フィルター、射影、ソート内)がインデックス自体に存在する場合に発生します。これが発生すると、MongoDBは実際のドキュメントをフェッチする必要がなくなります(COLLSCANが回避され、totalDocsExaminedは0または非常に低くなります)。

explain()出力では、カバリングインデックスにより、ステージがIXSCANを示し、totalDocsExaminedが0になります。

ハードウェアと設定の確認

totalKeysExaminedtotalDocsExaminedが妥当に見えてもレイテンシが高いままの場合は、クエリの形状以外を確認してください。ワーキングセットがメモリに収まっているか、ディスクレイテンシが高くないか、サーバーが書き込み負荷、ロック競合、またはCPU飽和状態にないかを確認してください。

まとめ

MongoDBのスロークエリを診断することはループです。ワークロードをプロファイリングし、遅いクエリを説明し、インデックスを追加または調整し、再度測定します。適切な修正により、検査されるドキュメントが減り、回避可能なコレクションスキャンやブロッキングソートが排除され、ユーザーが感じる実際のリクエストパスが改善されます。

実践可能なチェックリスト:

  1. プロファイラを一時的に有効にしてスロークエリをキャプチャします(slowms)。
  2. 問題のあるクエリをexplain('executionStats')を使用して実行します。
  3. COLLSCANまたは高いtotalDocsExaminedを確認します。
  4. ESRルールに基づいて複合インデックスを作成または変更し、フィルターとソートをカバーします。
  5. explain()コマンドを再実行して改善を確認します。