0

Spring の MongoTemplate を使用して MongoDB にアクセスします。

final Query query = new Query(Criteria.where("_id").exists(true));
query.with(new Sort(Direction.ASC, "FIRSTNAME", "LASTNAME", "EMAIL"));
if (count > 0) {
    query.limit(count);
}
query.skip(start);
query.fields().include("FIRSTNAME");
query.fields().include("LASTNAME");
query.fields().include("EMAIL");
return mongoTemplate.find(query, User.class, "users");

MongoDB で 400.000 レコードを生成しました。上記のソート行を使用せずに最初の 25 ユーザーを要求すると、50 ミリ秒以内に結果が得られます。

sort を使用すると、4 秒以上続きます。

次に、FIRSTNAME、LASTNAME、EMAIL のインデックスを作成しました。組み合わせたものではなく、単一のインデックス

mongoTemplate.indexOps("users").ensureIndex(new Index("FIRSTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("LASTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("EMAIL", Order.ASCENDING));

これらのインデックスを作成した後、クエリは再び 4 秒以上続きます。

私の間違いは何ですか?

-- 編集 MongoDB はこれをコンソールに書き込みます...

Thu Jul 04 10:10:11.442 [conn50] query mydb.users query: { query: { _id: { $exists: true } }, orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } } ntoreturn:25 ntoskip:0 nscanned:382424 scanAndOrder:1 keyUpdates:0 numYields: 2 locks(micros) r:6903475 nreturned:25 reslen:3669 4097ms
4

2 に答える 2

1

FIRSTNAMELASTNAME、およびの複合インデックスをEMAILこの順序で作成し、すべて昇順で作成する必要があります。

于 2013-07-04T08:33:57.963 に答える
0
Thu Jul 04 10:10:11.442 [conn50] query mydb.users query: 
{ query: { _id: { $exists: true } }, orderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } } 
ntoreturn:25 ntoskip:0 nscanned:382424 scanAndOrder:1 keyUpdates:0 numYields: 2 
locks(micros) r:6903475 nreturned:25 reslen:3669 4097ms

考えられる悪い兆候:

あなたの scanAndOrder は実現しつつあります ( scanAndOrder=1)。間違っていたら訂正してください。

返さなければなり(ntoreturn:25ません) は 25 文書を意味しますが、( nscanned:382424) 382424 文書をスキャンしています。

nscanned は Mongo がスキャンした範囲内のインデックス キーの数、nscannedObjects は最終結果を得るために参照したドキュメントの数です。nscannedObjects には、少なくとも返されたすべてのドキュメントが含まれます。Mongo がインデックスを確認するだけで、ドキュメントが確実に一致することがわかったとしてもです。したがって、常に nscanned >= nscannedObjects >= n であることがわかります。

質問の文脈:

ケース 1:上記のソート行を使用せずに最初の 25 ユーザーを要求すると、50 ミリ秒以内に結果が得られます。

ケース 2: sort を使用すると、4 秒以上続きます。

query.with(new Sort(Direction.ASC, "FIRSTNAME", "LASTNAME", "EMAIL"));

この場合、インデックスはありません: したがって、ここで述べたように実行されます:

これは、MongoDB がメモリ内のすべての結果をバッチ処理し、並べ替えてから返す必要があったことを意味します。不幸はたくさんあります。まず、サーバーの RAM と CPU を消費します。また、結果をバッチでストリーミングする代わりに、Mongo はすべての結果を一度にネットワークにダンプするだけで、アプリ サーバーの RAM に負担がかかります。最後に、Mongo はメモリ内でソートするデータに 32MB の制限を適用します。

ケース 3: FIRSTNAME、LASTNAME、EMAIL のインデックスを作成しました。組み合わせたものではなく、単一のインデックス

まだインデックスからデータをフェッチしていないと思います。ソート順に従ってインデックスを調整する必要があります

ソート フィールド (昇順/降順は、複数のソート フィールドがある場合のみ重要です)

Add sort fields to the index in the same order and direction as your query's sort

詳細については、この http://emptysqua.re/blog/optimizing-mongodb-compound-indexes/を確認してください。

考えられる答え:

クエリorderby: { LASTNAME: 1, FIRSTNAME: 1, EMAIL: 1 } }の並べ替え順序は、で指定した順序とは異なります。

mongoTemplate.indexOps("users").ensureIndex(new Index("FIRSTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("LASTNAME", Order.ASCENDING));
mongoTemplate.indexOps("users").ensureIndex(new Index("EMAIL", Order.ASCENDING));

Spring API が順序を保持していない可能性があると思います: https://jira.springsource.org/browse/DATAMONGO-177

複数のフィールドでソートしようとすると、フィールドの順序が維持されません。Sort クラスは LinkedHashMap の代わりに HashMap を使用しているため、返される順序は保証されません。

Spring jar バージョンについて教えてください。

これがあなたの質問に答えることを願っています。

私は少しさびているので、私が間違っているかもしれないと思うところを修正してください。

于 2013-07-04T08:24:49.977 に答える