Rails + Mongoid生产中的查询速度慢

时间:2014-11-18 19:56:11

标签: ruby-on-rails ruby performance mongodb mongoid

我遇到了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记录),因此对于为什么查询速度太慢而感到困惑。正如您所看到的,我已经在集合中添加了索引,因此我不知道如何提高查询速度。非常感谢帮助!谢谢!

1 个答案:

答案 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会显示您是否正在使用计划部分下的索引。