データが大きくなると、どのタイプのデータベースでもパフォーマンスの問題に直面します。問題のあるクエリの書き換えやデータベーススキーマの分析/最適化などの簡単な手順で、データベースのパフォーマンスを大幅に向上させることができます。 MongoDBは、DBAにとってこのプロセスを非常に簡単にするいくつかの優れた機能を提供します。たとえば、Query Profiler、Mongostat、Mongotop、優れたロギングサポートなど。
ほとんどの場合、クエリの実行方法を決定するのはデータベースシステムです。ユーザーは、クエリ言語を介して、必要な結果に関する詳細を提供するだけです。この記事では、MongoDBクエリプロファイラーを使用して、低速でリソースを大量に消費するクエリを見つける方法について説明します。 MongoDB Profilerは、実際のクエリレベルの洞察を提供する組み込みツールです。これにより、データベースシステムによって実行されているすべてのクエリを分析できます。
MongoDBプロファイラーの有効化/構成
通常、プロファイラーはすべてのデータをsystem.profileコレクションに格納します。このコレクションは、他の通常のMongoDBコレクションと同様にクエリできます。プロファイラーには3つのプロファイリングレベルがあります。デフォルトでは、どのデータベースでもプロファイラーレベルは0に設定されています。
次のコマンドを実行して、プロファイラーに関する情報を取得できます。
-
現在のプロファイリングレベルを取得します。
出力:db.getProfilingLevel()
0
-
現在のプロファイリングステータスを確認するには
出力:db.getProfilingStatus()
{ "was" : 0, "slowms" : 100 }
-
プロファイリングレベルを設定するには
出力:db.setProfilingLevel(1, 40)
{ "was" : 0, "slowms" : 100, "ok" : 1 }
MongoDBは古いプロファイリングレベルを出力し、OKを返します。これは、プロファイリングレベルが現在1に設定されていることを意味します。
Slowmsはプロファイラーのしきい値です。これは、プロファイラーが実行にしきい値よりも時間がかかるすべてのクエリをログに記録することを意味します。
プロファイラー出力について
このコマンドを実行して、system.profileコレクションから1つのドキュメントを取得します。
db.system.profile.find().limit(1).pretty()
出力:
{
"op" : "query",
"ns" : "mydb.Log",
"query" : {
"find" : "Log",
"filter" : {
"EMP_ID" : "01778"
}
},
"keysExamined" : 0,
"docsExamined" : 90022,
"cursorExhausted" : true,
"keyUpdates" : 0,
"writeConflicts" : 0,
"numYield" : 703,
"locks" : {
"Global" : {
"acquireCount" : {
"r" : NumberLong(1408)
}
},
"Database" : {
"acquireCount" : {
"r" : NumberLong(704)
}
},
"Collection" : {
"acquireCount" : {
"r" : NumberLong(704)
}
}
},
"nreturned" : 60,
"responseLength" : 17676,
"protocol" : "op_command",
"millis" : 40,
"execStats" : {
"stage" : "COLLSCAN",
"filter" : {
"EMP_ID" : {
"$eq" : "01778"
}
},
"nReturned" : 60,
"executionTimeMillisEstimate" : 30,
"works" : 90024,
"advanced" : 60,
"needTime" : 89963,
"needYield" : 0,
"saveState" : 703,
"restoreState" : 703,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 90022
},
"ts" : ISODate("2018-09-09T07:24:56.487Z"),
"client" : "127.0.0.1",
"allUsers" : [ ],
"user" : ""
}
これは、system.profileコレクションからの1つのドキュメントです。役立つ情報がたくさん含まれていることがわかります。このドキュメントの有用なフィールドのいくつかを理解しましょう。
- Opフィールドには、操作のタイプが格納されます。
- Nsフィールドにはターゲットデータベースとコレクション名が格納されます
- クエリフィールドには、クエリと結果に関する情報が格納されます。ドキュメントサイズが50KBを超える場合、結果は切り捨てられます
- keysExaminedは、クエリを実行するためにDBによって検査されたインデックスキーの数を格納します
- docsExaminedは、DBによって検査されたドキュメントの総数を格納します
- Nreturnedは、クエリによって返されたドキュメントの数を格納します
- Millisには、このクエリの実行にかかった実際の時間がミリ秒単位で含まれています
- Tsはクエリのタイムスタンプを保存します
これらのフィールドを調べてデータベースのパフォーマンスを最適化することにより、データベースシステムによってクエリ操作がどのように実行されたかに関する多くの情報を取得できます。たとえば、keysExamined値が「nreturns」値より大きい場合、DBが多くのインデックスをスキャンして結果を取得していることを示していますが、これは決して良い兆候ではありません。したがって、データベースインデックスを適切に調整する必要があります。
SomeninesがMongoDBDBAになる-MongoDBを本番環境に導入MongoDBDownloadを無料でデプロイ、監視、管理、スケーリングするために知っておくべきことを学びましょうプロファイラー出力を分析するための便利なクエリ
-
最も便利なクエリは、すべてのドキュメントをミリ単位で並べ替えて、遅いクエリのトップ10を取得することです。
db.system.profile.find().sort({millis:-1}).limit(10).pretty();
-
実行に30ミリ秒以上かかるすべてのクエリを検索します
db.system.profile.find({millis:{$gt:30}}).pretty()
-
最も遅い集計/コマンドクエリのトップ10を見つける
db.system.profile.find({op: {$eq: “command” }}).sort({millis:-1}).limit(10).pretty();
-
一部のドキュメントが移動されたすべての操作を検索します
db.system.profile.find({moved:true}).pretty()
-
データベースで大規模なスキャンを実行しているクエリを検索する
db.system.profile.find({docsExamined:{$gt:10000}}).pretty()
-
集計を使用して、各タイプの操作にかかる最大時間と平均時間を見つけます
db.system.profile.aggregate( { $group : { _id :"$op", count:{$sum:1}, "max_time":{$max:"$millis"}, "avg_time":{$avg:"$millis"} }}).pretty()
-
集計を使用して、各データベースのクエリにかかる最大時間と平均時間を見つけます
db.system.profile.aggregate( { $group : { _id :"$ns", count:{$sum:1}, "max_time":{$max:"$millis"}, "avg_time":{$avg:"$millis"} }}.pretty()
結論
MongoDB Profilerは、データベースがクエリ/コマンドを実行する方法についての洞察を得るのに非常に便利なツールです。本番環境でプロファイラーを使用する場合は、適切なテストを行う必要があります。これは、特にすべてのクエリをログに記録する場合、つまりプロファイリングレベルが2に設定されている場合に、データベースのスループットに影響を与える可能性があるためです。遅いという意味です。すべてのクエリを低速と見なすことができるかどうかを判断する必要があります。これに基づいて、クエリをログに記録するための最小しきい値を設定できます。これにより、このツールを使用した場合のDBパフォーマンスへの影響が軽減されます