我遇到了Mongoid查询的一些性能问题,特别是在生产中。 我最初的原因是它与托管有关(在最小的Linode实例上)但是当我迁移到更大的实例时,查询速度略有提升。为了比较起见,产品页面需要大约800毫秒 - 1000毫秒才能加载到生产中(开发时间为60毫秒)但是在托管迁移之后,它会在生产中徘徊大约300毫秒到800毫秒。这使我相信缓慢是由低效查询以及可能的n + 1副作用引起的。以下是我点击产品API时所发生情况的快照:
MOPED: 173.255.252.208:27017 QUERY database=* collection=orders selector= {"$query"=>{"user_id"=>"52cc529eec5cb38bbf000001"}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil (20.6976ms)
MOPED: 173.255.252.208:27017 QUERY database=* collection=orders selector={"$query"=>{"user_id"=>"52cc529eec5cb38bbf000001"}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil (13.5436ms)
MOPED: 173.255.252.208:27017 COMMAND database=* command={:count=>"orders", :query=>{"user_id"=>"52cc529eec5cb38bbf000001"}} (18.1813ms)
MOPED: 173.255.252.208:27017 QUERY database=* collection=orders selector={"$query"=>{"user_id"=>"52cc529eec5cb38bbf000001"}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil (15.9233ms)
MOPED: 173.255.252.208:27017 QUERY database=* collection=orders selector={"$query"=>{"user_id"=>"52cc529eec5cb38bbf000001"}, "$orderby"=>{:_id=>1}} flags=[] limit=-1 skip=0 batch_size=nil fields=nil (29.9242ms)
MOPED: 173.255.252.208:27017 QUERY database=* collection=orders selector={"$query"=>{"user_id"=>"52cc529eec5cb38bbf000001"}, "$orderby"=>{:_id=>1}} flags=[] limit=0 skip=0 batch_size=nil fields=nil (69.3288ms)
似乎这是造成缓慢的主要因素,但是,为什么查询Orders集合的速度如此之慢?以下是Mongodb的统计数据:
db.orders.stats()
{
"ns" : "orders",
"count" : 21535,
"size" : 15068736,
"avgObjSize" : 699.7323426979336,
"storageSize" : 23617536,
"numExtents" : 7,
"nindexes" : 3,
"lastExtentSize" : 9555968,
"paddingFactor" : 1.025000000000004,
"systemFlags" : 1,
"userFlags" : 0,
"totalIndexSize" : 5567856,
"indexSizes" : {
"_id_" : 711312,
"order_number_index" : 972944,
"_keywords_1" : 3883600
},
"ok" : 1
}
集合本身看起来很小(22k记录),因此对于为什么查询速度太慢而感到困惑。正如您所看到的,我已经在集合中添加了索引,因此我不知道如何提高查询速度。非常感谢帮助!谢谢!
答案 0 :(得分:0)
当您通过user_id查询订单时,在user_id上添加索引可能是个好主意。索引{ user_id: 1 }
应该没问题。
如果您在应用中发布了相关代码,则可以更轻松地判断它是否为n + 1查询。但是,它看起来确实如此,因为您多次查询订单集合;更有效的查询是选择user_id位于user_id数组中的订单。有关预先加载的mongoid文档,请参阅here。从本质上讲,如果您通过User.all.each { |u| puts u.orders }
之类的方式对用户的订单进行迭代,只需在.includes(:orders)
之前添加.each
即可提高效率。
如果您仍然遇到缓慢问题,那么可能值得采用查询数据库并在控制台中运行.explain
的代码行。请参阅here以获取有关理解结果的帮助,或here如果您使用的是2.6而不是3.0。最重要的是要扫描的文档数量与输出中符合条件的文档数量。例如,如果您有21535个文档而且没有user_id索引,那么您每次都可能扫描所有21535个文档以查找与该user_id匹配的文档。添加索引后,.explain
会显示您是否正在使用计划部分下的索引。