sql >> データベース >  >> NoSQL >> MongoDB

500万を超えるレコードのパフォーマンスをクエリするMongoDB

    これは干し草の山の中の針を探しています。 Explain()の出力が必要です うまく機能しないクエリの場合。残念ながら、それでもその特定のクエリでのみ問題が解決するので、これにアプローチする方法についての戦略を次に示します。

    1. RAMが不十分でページングが多すぎることが原因ではないことを確認してください
    2. DBプロファイラーを有効にします( db.setProfilingLevel(1、timeout)を使用します ここで、 timeout クエリまたはコマンドにかかるミリ秒数のしきい値です。遅いものはログに記録されます)
    3. db.system.profileで遅いクエリを調べます Explain()を使用して手動でクエリを実行します
    4. Explain()で遅い操作を特定してみてください scanAndOrderなどの出力 または大きなnscanned 、など
    5. クエリの選択性に関する理由と、インデックスを使用してクエリを改善できるかどうか 。そうでない場合は、エンドユーザーのフィルター設定を禁止するか、操作が遅い可能性があることを警告するダイアログを表示することを検討してください。

    重要な問題は、明らかにユーザーがフィルターを自由に組み合わせることができるようにしていることです。インデックスが交差しないと、必要なインデックスの数が大幅に増加します。

    また、考えられるすべてのクエリで盲目的にインデックスをスローすることは、非常に悪い戦略です。クエリを構造化し、インデックス付きフィールドに十分な選択性があることを確認することが重要です。 。

    statusを持つすべてのユーザーに対するクエリがあるとします。 「アクティブ」およびその他の基準。ただし、500万人のユーザーのうち、300万人がアクティブで、200万人がアクティブではないため、500万を超えるエントリには2つの異なる値しかありません。このようなインデックスは通常役に立ちません。最初に他の基準を検索してから、結果をスキャンすることをお勧めします。平均して、100個のドキュメントを返す場合、167個のドキュメントをスキャンする必要があります。これにより、パフォーマンスが大幅に低下することはありません。しかし、それはそれほど単純ではありません。主な基準がjoined_atの場合 ユーザーの日付とユーザーが時間の経過とともに使用を中止する可能性が高いため、数千をスキャンしなければならなくなる可能性があります 百の一致を見つける前にドキュメントの。

    したがって、最適化はデータに大きく依存します(構造だけでなく) 、だけでなく、データ自体 )、その内部相関とクエリパターン

    データがRAMに対して大きすぎると、状況はさらに悪化します。インデックスを持つことは素晴らしいことですが、結果をスキャンする(または単に返す)には、ディスクから大量のデータをランダムにフェッチする必要があり、これには多くの時間がかかります。

    これを制御する最善の方法は、さまざまなクエリタイプの数を制限し、選択性の低い情報に対するクエリを禁止し、古いデータへのランダムアクセスを防止することです。

    他のすべてが失敗し、フィルターにそれほどの柔軟性が本当に必要な場合は、インデックスの交差をサポートする別の検索DBを検討し、そこからmongo IDをフェッチして、 $in<を使用してmongoから結果を取得することをお勧めします。 / code> 。しかし、それはそれ自身の危険に満ちています。

    -編集-

    あなたが投稿した説明は、低選択性フィールドのスキャンに関する問題の美しい例です。どうやら、「[email protected]」のドキュメントはたくさんあります。現在、これらのドキュメントを検索し、タイムスタンプの降順で並べ替えることは、選択性の高いインデックスでサポートされているため、非常に高速です。残念ながら、デバイスタイプは2つしかないため、mongoは30060ドキュメントをスキャンして、「モバイル」に一致する最初のドキュメントを見つける必要があります。

    これはある種のWebトラッキングであり、ユーザーの使用パターンによってクエリが遅くなると思います(毎日モバイルとWebを切り替えると、クエリは速くなります)。

    この特定のクエリを高速化するには、デバイスタイプを含む複合インデックスを使用します。使用

    a) ensureIndex({'username': 1, 'userAgent.deviceType' : 1, 'timestamp' :-1})
    

    または

    b) ensureIndex({'userAgent.deviceType' : 1, 'username' : 1, 'timestamp' :-1})
    

    残念ながら、これは find({"username": "foo"})。sort({"timestamp":-1});のようなクエリを意味します 同じインデックスを使用できなくなったため、説明したように、インデックスの数は急速に増加します。

    現時点では、mongodbを使用したこれに対する非常に良い解決策はありません。



    1. Redis:データベースに保存されているすべての値を返します

    2. mongodb c#ドライバーでPOCOを使用するときに_idフィールドを管理する方法

    3. 参照モデルのフィールドごとのモデルに対するマングースのネストされたクエリ

    4. NodeJSで、異なるフィールド名を持つmongodbから結果を出力するにはどうすればよいですか?