3

** アップデート **

問題であることが確認されたので回答を投稿しました

** オリジナル **

まず、お詫び申し上げます。昨日MongoDBを使い始めたばかりですが、まだかなり新しいです。私は非常に単純なクエリを持っています、そしてPHPを使って私の発見はこれです:

Mongoのバージョンは2.0.4で、CentOS 6.2(Final)x64で実行されます。

$start = microtime(true);
$totalactive = $db->people->count(array('items'=> array('$gt' => 1)));
$end = microtime(true);
printf("Query lasted %.2f seconds\n", $end - $start);

インデックスがない場合は、次を返します。

Query lasted 0.15 seconds

私はデータベースの人々に280,000のレコードを持っています。したがって、このデータを頻繁に照会するため、「アイテム」にインデックスを追加すると役立つはずだと思いました。しかし、私の信じられないことに、インデックスを追加した後、私はこれを取得します:

Query lasted 0.25 seconds

私は何か間違ったことをしていますか?

countの代わりに、findを使用して説明を取得しました。これは出力です。

> db.people.find({ 'items' : { '$gte' : 1 } }).explain();
{
"cursor" : "BtreeCursor items_1",
"nscanned" : 206396,
"nscannedObjects" : 206396,
"n" : 206396,
"millis" : 269,
"nYields" : 0,
"nChunkSkips" : 0,
"isMultiKey" : false,
"indexOnly" : false,
"indexBounds" : {
    "items" : [
        [
            1,
            1.7976931348623157e+308
        ]
    ]
}
}

クエリを「$ne」0に変更すると、さらに10ミリ秒かかります。

コレクションの統計は次のとおりです。

> db.people.stats()
{
"ns" : "stats.people",
"count" : 281207,
"size" : 23621416,
"avgObjSize" : 84.00009957077881,
"storageSize" : 33333248,
"numExtents" : 8,
"nindexes" : 2,
"lastExtentSize" : 12083200,
"paddingFactor" : 1,
"flags" : 0,
"totalIndexSize" : 21412944,
"indexSizes" : {
    "_id_" : 14324352,
    "items_1" : 7088592
},
"ok" : 1
}

私は1GBのRAMを解放しているので、インデックスはメモリに収まると思います。

リクエストに応じて、ピープルインデックスは次のようになります。

> db.people.getIndexes()
[
{
    "v" : 1,
    "key" : {
        "_id" : 1
    },
    "ns" : "stats.people",
    "name" : "_id_"
},
{
    "v" : 1,
    "key" : {
        "items" : 1
    },
    "ns" : "stats.people",
    "name" : "items_1"
}
]
4

5 に答える 5

1

これは、MongoDBエンジンのバグまたは最適化が必要なものであることが確認されました。これをmongoメーリングリストに投稿し、EliotHorowitzから受け取った応答

これは間違いなくバグであり、少なくとも、より適切に最適化できるパスです。ケースを作成しました:https ://jira.mongodb.org/browse/SERVER-5607

Priority:  Major
Fix Version/s: 2.3 desired
Type:  Bug

これがバグであることを確認するのを手伝ってくれた人たちに感謝します=)

于 2012-04-15T13:41:21.010 に答える
1

インデックスを持つことは、2つの理由で有益です。

  1. コレクションのごく一部にのみアクセスする場合(インデックスで満たすことができる制限フィルターのため)。経験則は10%未満です。

  2. コレクションにまったくアクセスする必要がない場合(フィルタリングと結果セットの両方で、必要なすべてのデータがインデックスにあるため)。これは「indexOnly=true」で示されます。

「検索」クエリの場合、これは両方とも当てはまりません。コレクションのほぼ全体(281207のうち206396)にアクセスしており、すべてのフィールドデータが必要です。したがって、最初にインデックスを調べ、次にコレクションのほぼ全体を調べて、インデックスの目的を無効にします。コレクション全体を読むだけの方が速かったでしょう。

「count」クエリのパフォーマンスが向上することを期待していました(インデックスを調べるだけで満たすことができるため)。それについても説明してもらえますか?

于 2012-04-13T02:53:31.103 に答える
1

Look at this:

http://www.mongodb.org/display/DOCS/Indexing+Advice+and+FAQ#IndexingAdviceandFAQ-5.MongoDB%27s%24neor%24ninoperator%27saren%27tefficientwithindexes.

Which made me consider this solution. How about this?

$totalactive = $db->people->count() - $db->people->count(array('items'=> array('$eq' => 1)));
于 2012-04-13T03:10:21.760 に答える
0

これは、クエリがほぼ完全なコレクション スキャンであるためです。クエリ オプティマイザは、最適なパフォーマンスのためにインデックスを使用すべきではないときに、インデックスを使用することを選択しています。はい、直感に反しますが、カーソルがインデックス B ツリーをウォークし、ツリーが指すドキュメントを取得しているためです。これは、ほぼツリー全体をスキャンする必要がある場合、コレクションをウォークするよりも遅くなります。

この種のクエリを本当に実行する必要があり、そのインデックスを並べ替えなどの他の目的に使用する場合は.hint({$natural: 1})、 を使用して、インデックスを使用しないようにクエリに指示できます。

偶然にも、最近のブログ投稿で同様の問題について投稿しました: http://wes.skeweredrook.com/testing-with-mongodb-part-1/

于 2012-04-14T23:11:36.703 に答える
0

このコレクションのオブジェクトの例を教えてください。「アイテム」フィールドは配列ですか? もしそうなら、新しいフィールド「itemCount」を追加して、それにインデックスを付けることをお勧めします。このフィールドで $gt を実行すると、非常に高速になります。

于 2012-04-13T13:48:43.563 に答える