web-dev-qa-db-ja.com

MongoDB 'count()'は非常に遅いです。どうすればそれを改善/回避できますか?

私は現在、数百万のデータレコードでMongoDBを使用しています。かなり面倒なことが1つ見つかりました。

クエリされたデータコレクションの数が少ない場合に 'count()'関数を使用すると、非常に高速です。ただし、クエリされたデータコレクションに数千または数百万ものデータレコードが含まれている場合、システム全体が非常に遅くなります。

必須フィールドにインデックスを付けたことを確認しました。

誰かが同じものに遭遇しましたか?それをどのように改善しますか?

54
Winston Chen

現在、適切なインデックスを作成する以外の最適化があります。

_db.users.ensureIndex({name:1});
db.users.find({name:"Andrei"}).count();
_

いくつかのカウンタが必要な場合は、可能な限り事前計算することをお勧めします。アトミック $ inc 操作を使用し、count({})を使用しない。

しかし、mongodbのメンバーはmongodbに一生懸命取り組んでいるので、jira bug に従ってmongodb 2.1で計画しているcount({})の改善です。

31
Andrew Orsich

インデックスがディスクアクセスなしで実際に使用されていることを確認できます。

名前が「Andrei」のレコードをカウントするとします。

名前にインデックスを付けて(完了したように)、

db.users.find({name:"andrei"}, {_id:0, name:1}).count()

次のことをチェックすることで、それが最速のカウント方法であることを確認できます(事前計算を除く)。

db.users.find({name:"andrei"}, {_id:0, name:1}).explain() 

trueに設定されたindex_onlyフィールドを表示します。

このトリックにより、クエリがディスクからではなくRAM(インデックス)からのみレコードを取得するようになります。

10
kamaradclimber

私にとっての解決策は、インデックスをsparseに変更することでした。特定の状況に依存しますが、可能であれば試してみてください。

db.Account.createIndex( { "date_checked_1": 1 }, { sparse: true } )

db.Account.find({    
     "dateChecked" : { $exists : true }    
}).count()

コレクション内の318千件のレコード

  • 0.31秒-疎インデックス付き
  • 0.79秒-非スパースインデックス付き
7
Vaclav Kohout

あなたは今のところほとんど運がありません。mongodbの数はひどく、近い将来良くなることはありません。参照: https://jira.mongodb.org/browse/SERVER-1752

経験から、それが一度限りのものであるか、非常にまれにしか発生しないか、データベースがかなり小さい場合を除き、ほとんど使用しないでください。

@Andrew Orsichが述べたように、可能な限りカウンターを使用します(カウンターの低下はグローバルな書き込みロックですが、それでもcount()よりも優れています)。

5
Travis Reeder