Mongoid到Mongo查询翻译

时间:2013-12-16 17:52:55

标签: mongodb mongoid mongoid3

通过更简单的解释更新此问题。

对于我的数据,以下Mongo CLI查询需要208ms。此查询检索18个请求对象的所有数据。

db.videos.find({avg_rating:{$ gt:1},poster_large_thumb:{$ exists:true},release_date:{$ lte:ISODate(“2000-12-31”)}})。sort( {release_date:-1,avg_rating:-1,title:1})。skip(30).limit(18).pretty()。explain()

{
    "cursor" : "BasicCursor",
    "nscanned" : 76112,
    "nscannedObjects" : 76112,
    "n" : 48,
    "scanAndOrder" : true,
    "millis" : 208,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : false,
    "indexOnly" : false,
    "indexBounds" : {

    }
}

然而,当我进行查询时,使用Mongoid会创建一个没有实际数据的条件对象。我将此标准传递给迭代它以创建JSON数据结构的方法。由于需要数据,因此必须从数据库中检索每个对象。以下是返回查询的条件:

@videos = Video.order_by(release_date:-1,avg_rating:-1,title:1).where(:avg_rating.gt => 1,:poster_large_thumb.exists => 1,:release_date.lte = > start_date).skip(skip * POSTERS_PER_ROW).limit(limit * POSTERS_PER_ROW)

当我迭代@videos时,每个对象需要240多秒来从数据库中检索,这来自一些调试输出。

Getting one object: 
2013-12-18 00:43:52 UTC
2013-12-18 00:43:52 UTC
0.24489331245422363

假设如果我获得了Video.order_by(...)查询中的所有数据,那么总共需要208ms,我如何强制它在一个查询中执行检索而不是单独获取每个对象?

这里的一些东西导致整个检索比Mongo CLI多了几个数量级。

2 个答案:

答案 0 :(得分:1)

对策:

  1. skip()。limit()查询在MongoDB端往往变得越来越慢。当跳过文档时,有关详细信息,请参阅此处https://stackoverflow.com/a/7228190/534150

  2. 多个相同的查询在我看来是一个N + 1类型的问题。这意味着,在您的视图中,您可能有一个循环调用延迟加载的属性,因此它会一遍又一遍地发送查询。这些问题通常很难找到,但要跟踪它们,您需要拥有端到端的跟踪,您可能是唯一能够做到这一点的跟踪,因为您可以访问源代码。

    < / LI>
  3. Mongoid方面对我来说是正确的。

答案 1 :(得分:0)

感谢这些想法,我认为@Arthur给出了重要的暗示。没有人能够回答,因为看起来问题出现在另一个代码中 - 我如何访问标准。

给出以下查询,它产生一个标准:

@videos = Video.order_by(release_date: 1, avg_rating: 1, title: -1).where(:release_date.ne => 0,:avg_rating.gt => 1, :poster_large_thumb.exists => 1, :release_date.gt => start_date).skip(skip*POSTERS_PER_ROW).limit(limit*POSTERS_PER_ROW).only(:_id, :poster_large_thumb, :title)  

在一个嵌套的块中,我用一行代码来抓取值:

video_full = @videos[((row_index)*POSTERS_PER_ROW)+column_index]

这种随机访问符号似乎是个问题。它似乎为每个单独的对象执行完整的Moped查询,因此POSTERS_PER_ROW * num_rows次。

如果我使用这段代码抓住循环之前的所有视频:

@videos.each do |video|
    videos_full.push video
end

然后从数组中获取值而不是像这样的条件:

video_full = videos_full[((row_index)*POSTERS_PER_ROW)+column_index]

我只获得一个248毫秒的Moped查询,所有对象都使用该查询检索。这是一个巨大的加速。查询时间从num_rows * POSTERS_PER_ROW * 248ms变为仅248ms

这对我来说是一个很大的教训,所以如果有人可以指出描述这种效果的文档以及要遵循的规则,我一定会很感激。