Mongoid:为什么获取计数比获取文档要慢

时间:2013-03-07 01:32:42

标签: mongodb mongoid

我注意到一种奇怪的行为。它可能是mongoid或mongodb,我不确定,但Counting文档比获取文档要慢。以下是我解雇的查询:

Institution.all.any_of(:portaled_at.ne => nil).any_of(portaled: true).order_by(:portaled_at.desc).count
# mongodb query and timing as per mongoid logs, 
# times are consistent over multiple runs
# MONGODB (236ms) db['$cmd'].find({"count"=>"institutions", "query"=>{"$or"=>[{:portaled_at=>{"$ne"=>nil}}, {:portaled=>true}]}, "fields"=>nil}).limit(-1)
# MONGODB (245ms) db['$cmd'].find({"count"=>"institutions", "query"=>{"$or"=>[{:portaled_at=>{"$ne"=>nil}}, {:portaled=>true}]}, "fields"=>nil}).limit(-1)

Institution.all.any_of(:portaled_at.ne => nil).any_of(portaled: true).order_by(:portaled_at.desc).to_a
# mongodb query and timing as per mongoid logs
# times are not so consistent over multiple runs,
# but consistently much lower than count query
# MONGODB (9ms) db['institutions'].find({"$or"=>[{:portaled_at=>{"$ne"=>nil}}, {:portaled=>true}]}).sort([[:portaled_at, :desc]])
# MONGODB (18ms) db['institutions'].find({"$or"=>[{:portaled_at=>{"$ne"=>nil}}, {:portaled=>true}]}).sort([[:portaled_at, :desc]])

我认为mongodb不会为$and$or查询使用索引,但是如果重要的话,我在portaled_at上有一个稀疏索引,按降序排列。在大约200,000个文档中,只有大约50-60个文档设置了portaled_at。

  • rails 3.2.12
  • mongoid 2.6.0
  • mongodb 2.2.3

这违反了我的常识,如果有人能够解释发生了什么,我会非常感激。

2 个答案:

答案 0 :(得分:4)

虽然两者在MongoDB中运行不同的子系统(一个使用runCommand而另一个使用标准查询引擎),但在这种情况下,特定问题很可能是当前版本的MongoDb中的已知问题。

快速摘要是没有提取的计数非常slow,因为MongoDb正在做很多额外的工作,而这些工作通常是不必要的。它已在开发分支中修复,因此它应该在2.4发布时。

答案 1 :(得分:0)

出于某种原因,Mongo默认不使用索引来计算记录。但是,如果正确构造查询,Mongo将从索引计数。诀窍是只获取索引中的字段,并且必须指定查询。

在Mongo Shell中:

db.MyCollection.find({"_id":{$ne:''}},{"_id":1}).count()

您可以查看说明方法:

db.MyCollection.find({"_id":{$ne:''}},{"_id":1}).explain()

在输出中包含"indexOnly" : true

类似地,命令可以通过Moped驱动程序直接执行,如下所示:

Mongoid::Sessions.default.command(:count => "MyCollection", :query=>{"_id"=>{"$ne"=>""}}, :fields => {:_id=>1})

其中,在我的基准测试中(在我的实时数据中,YMMV)比简单地执行MyMongoidDocumentClass.count

快约100倍

不幸的是,似乎没有办法通过Mongoid gem快速做到这一点。