データベース
 Computer >> コンピューター >  >> プログラミング >> データベース

MongoDBで未使用のインデックスを検索する

MongoDBで未使用のインデックスを検索する

バージョン3.2以降、MongoDBはすべてのインデックスの使用統計を追跡します。これらの統計にアクセスするために、MongoDBは$indexStats集約パイプラインステージを提供します。 MongoDBで未使用のインデックスを見つける際の6つの考慮事項を次に示します。

たとえば、次のコマンドは、コレクション「test.foo」のインデックス統計を提供します。

db.foo.aggregate( [ { $indexStats: { } } ] )

https://bit.ly/2seXnzo

$ indexStatsの出力については説明しません。このトピックをカバーするドキュメントがたくさんあり、優れた記事がたくさんあるからです。代わりに、$ indexStats演算子を使用するときに、さまざまな領域について6つの考慮事項を提供します。

考慮事項1:統計はサービスを再起動するたびにリセットされます

$ indexStats演算子を使用するときは、常に「accesses.since」フィールドに特に注意してください。 1日の終わりのバッチ処理や週次レポートなど、一部のクエリパターンはまれである可能性があるため、評価する統計の期間がニーズをカバーしていることを確認してください。次のスクリプトを使用すると、しきい値(時間単位)を設定でき、未使用のインデックスが準拠していない場合は警告が出力されます。

threshold_hours=24; 

db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops==0) 
{if (ISODate()-f.accesses.since < threshold_hours*3600*1000) {print('Index: ' +f.name+ ' accessed: 
' +f.accesses.ops+ ' times, Status:WARNING, The duration of statistics DOES NOT meet your compliance')} 
else {print('Index: ' +f.name+ ' accessed: ' +f.accesses.ops+ ' times,  Status:OK The duration of 
statistics meet your compliance');};}})

あなたにとって正しいしきい値は何ですか?簡単な答えはありません。すべてのステートメントパターンが同じ頻度で実行されるわけではないため、適切なしきい値はアプリケーションごとに異なり、同じデータベース内のコレクションごとに異なる場合もあります。

考慮事項2:二次読み取り

デフォルトでは、$indexStatsはプライマリから読み取ります。アプリケーションがセカンダリからのみ読み取る場合、プライマリに対して$ indexStatsを実行すると、誤った結論につながります。セカンダリからの結果を読み取るには、上記の最初の考慮事項のスクリプトを使用できますが、 db.getMongo()。setReadPref(‘secondary’)を実行します。 実行する前に、コマンドにセカンダリからの読み取りを強制します。

ここでの問題は、「コレクションがプライマリ読み取りとセカンダリ読み取りの両方を受信した場合はどうなるか」です。次のスクリプトを使用して、プライマリとセカンダリの両方で使用されていないインデックスをidx配列に入力できます。

idx=[];

db.foo.getIndexes().forEach(function(f){idx.push(f.name)})
db.getMongo().setReadPref('primary');
db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops>0) 
{ var index = idx.indexOf(f.name); if (index > -1) {idx.splice(index, 1);};}})
db.getMongo().setReadPref('secondary');
db.foo.aggregate( [ { $indexStats: { } } ] ).forEach(function(f){if (f.accesses.ops>0) 
{ var index = idx.indexOf(f.name); if (index > -1) {idx.splice(index, 1);};}})
>

idx配列の内容には、プライマリとセカンダリの両方で未使用のインデックスが含まれます。コンプライアンスウィンドウ(threshold_hours)はどうですか?考慮事項1(前のサブセクション)からスクリプトを少し変更すると、時間コンプライアンスを適用できるようになります。集計部分を以下に示すものに置き換え、setReadPrefを使用してプライマリとセカンダリに対してスクリプトを実行するだけです:

db.foo.aggregate( [ { $indexStats: { } } ,{$match:{"name" : {$in:idx}}}] ).

プライマリとセカンダリが異なるコンプライアンス結果を返す場合、最善のアプローチは、両方の層が準拠するのを待つことです。

セカンダリ読み取り設定を使用すると、セカンダリが最近再起動され、スクリプトがそのセカンダリを選択して統計をプルする場合、「誤った結果」が発生する可能性があります。この場合、適切なアプローチは db.serverStatus()。uptimeを確認することです。 稼働時間が長いセカンダリを選択します。稼働時間の方法では、このブログ投稿の将来のリビジョンで実装されるスクリプトに対して別のアプローチが必要です。

考慮事項3:レプリカセットタグ

レプリカセットタグは多くのユースケースに適用できますが、主にジオレプリケーションシナリオでの読み取りの局所性と、特定のワークロードを専用ノードにターゲティングするために使用されます(例:大量の分析操作)。ワークロードターゲティングに関しては、タグ付けされたノードは、他のノードが使用しない1つまたは複数のインデックスを使用する可能性があるため、個別に調べる必要があります。これは、ジオレプリケーションにも当てはまる可能性がありますが、よりまれです。考慮事項1のスクリプトは、スクリプトの最初にreadPreferenceを追加して、タグ付けされたメンバーをチェックするために使用できます。読み取りプリファレンスを分析用にマークされたセカンダリに設定する例を次に示します。

 db.getMongo().setReadPref('secondary', [ { "workload": "analytics" } ] ) .  

上記の2番目の考慮事項の最後の段落で説明されている将来のアプローチは、タグ付けされたセカンダリもチェックするように拡張できます。

考慮事項4:TTLインデックス

TTLインデックスは操作を提供しますが、その主な用途はデータのプルーニングです。 TTLモニターはインデックス操作としてカウントされないため、$indexStatsがこれらのインデックスを未使用として報告する可能性が非常に高くなります。 $ indexStatsレポートの結果に基づいてTTLインデックスを削除することは絶対に避けたいので、スクリプトはこのタイプのインデックスを除外する必要があります。

2番目のセクションのpopulateidx配列スクリプトを少し変更すると、その作業が実行されます。 2行目を次の行に置き換えると、idx配列にTTLインデックスが含まれなくなります。

db.foo.getIndexes().forEach(function(f){if (f.expireAfterSeconds==undefined) 
{idx.push(f.name)}})

除外されたインデックスについての議論をさらに一歩進めると、_idもこのカテゴリに分類されると主張できます。もちろん、未使用の場合でも_idインデックスを削除することはできません。 _idインデックスに決して触れないコレクションは、再設計が必要になる場合があります。

考慮事項5:シャードクラスター

シャーディングされたクラスターに関しては、$indexStatsの出力を評価する前に考慮すべき2つの項目があります。まず、シャードコレクションに対して$ indexStatsを使用すると、シャードキーインデックスが未使用として分類される可能性があります。たとえば、 {_ id:” hashed”}でシャーディングされた書き込みの多いコレクション (書き込みの均等な分散用)ただし、_idインデックスを利用できる読み取り/更新/削除操作はありません。この場合、 {_ id:” hashed”} 未使用として報告します。シャーディングされたクラスターが破損するため、インデックスを削除することはお勧めできません。 「stats.foo」コレクションのシャードキーを除外する場合は、考慮事項2(2次読み取り)で説明したメソッドに次のスクリプトを添付すると、シャードキーがidx配列から除外されます。

shardkey=db.getSiblingDB('config').collections.findOne({_id:'stats.foo'},{_id:0,key:1});
db.foo.getIndexes().forEach(function(f){if (JSON.stringify(f.key)!=JSON.stringify(shardkey.key)) 
{printjson(shardkey.key);printjson(f.key);idx.push(f.name)}})

もう1つの考慮事項は、$ indexStatsの出力に関連しています。これは、コレクションに存在するすべてのシャードから統計を返すようになったためです。まれですが、インデックスがいくつかのシャードで未使用であると報告され、他のシャードがそれを使用している場合があります。不十分なシャードキーが原因である可能性がありますが、最も一般的なシナリオは「インデックスのカバー」と呼ばれます。

カバーするインデックスをよりよく理解するための例を次に示します。インデックス{a:1}と{a:1、b:1}はどちらも、フィールド「a」で等式一致を提供できます。 shardAのオプティマイザが{a:1}を選択し、shardBが{a:1、b:1}を選択した場合、両方のインデックスは少なくとも1つのシャードに対して未使用を報告します。

課題は、グローバルに使用されていないインデックスを見つけることです。検討2スクリプト(2次読み取り)の集約部分(forEachループが続く)を次のスクリプトに置き換えると、次のようになります。

db.foo.aggregate( [ { $indexStats: { } } , {$group: {_id:"$name",number :
 {$sum:"$accesses.ops"}}}] ).forEach(function(f){if (f.number>0) { var index = idx.indexOf(f._id);
 if (index > -1) {idx.splice(index, 1);};}})

もう1つの課題は、部分的に使用されているインデックスを見つけることです。この情報は、冗長なインデックスまたはインデックス識別の誤動作に関して役立つ可能性があります。 idx配列を使用して、次の集計/スクリプトにグローバルに使用されていないインデックスが入力され、部分的に使用されているインデックスが報告されます。

db.foo.aggregate( [ { $indexStats: { } 
},{$match:{name:{$nin:idx},"accesses.ops":0}}]).forEach(function(f){print("Index "+f.name+" 
reports as partially unused on shard/host " +f.host)})

考慮事項6:使用頻度の低いインデックス

未使用のインデックスを見つけて削除することは重要ですが、最も使用されていないインデックスを評価することも重要です。インデックスが1週間または1か月の間に1回または2回しかアクセスされない場合は、それがワークロードにとって必要または有益ではないことを意味している可能性があります。次の集計を使用して、使用頻度の低いインデックスを定期的にチェックすることをお勧めします。

db.foo.aggregate( [ { $indexStats: { } },{$match:{"accesses.ops":{$gt:0}}},{$group: 
{_id:"$name",number : {$sum:"$accesses.ops"}}},{$sort:{number:1}}] )

次に、適切なアクションを実行します。これには、インデックスを削除するか、インデックス定義を変更するか、スキーマ/アプリケーションロジックを変更してインデックスを冗長にすることができます。

私たちはあなたのためにここにいます

MongoDBインスタンスのインデックスをクリーンアップするお手伝いをします。 support@objectrocket.comへのチケットを作成し、インデックスの改善をお手伝いします。


  1. MongoDBコンパスの紹介

    この投稿では、MongoDBコンパスと呼ばれるMongoDB®のGUIを紹介します。 概要 Compassを使用すると、MongoDBクエリ構文を正式に知らなくても、MongoDBデータを分析して理解できます。 Compassを使用すると、視覚的な環境でデータを探索するだけでなく、クエリのパフォーマンスを最適化し、インデックスを管理し、ドキュメントの検証を実装できます。 コンパスエディション Compassには3つの主要なエディションがあります: コンパス :すべての機能を備えたフルバージョン。 コンパス読み取り専用 :すべての書き込みおよび削除機能が削除された、読み取り操作に

  2. MongoDBでのコードインジェクション

    元々は2019年3月5日に公開されました アプリケーション開発者、データベース管理者(DBA)、またはその他の技術者の場合は、コードインジェクションを監視する必要があります。 安全なクラウド環境があります。データベースアクセスがロックダウンされています。しかし、アプリケーションコードはどうですか?より安全であると考えられていますが、いいえ NoSQLiでは、注射できないという意味ではありません。 NoSQLは、他のデータベースコードと同じようにコードインジェクションの影響を受けやすい可能性があります。コードインジェクションを防止しないことは、ドアにセキュリティシステムを設置し、バックウ