【问题标题】:Mongoid to Mongo query translationMongoid 到 Mongo 查询翻译
【发布时间】:2013-12-19 01:17:08
【问题描述】:

这个问题更新了一个更简单的解释。

对于我的数据,以下 Mongo CLI 查询需要 208 毫秒。此查询检索 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(...) 查询中获取所有数据,总共需要 208 毫秒,我该如何强制它在一个查询中进行检索,而不是单独获取每个对象?

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

【问题讨论】:

  • 您的 mongod 日志将记录每一个耗时超过 100 毫秒的查询 - 您可以在那里看到它们的样子。

标签: mongodb mongoid mongoid3


【解决方案1】:

回复:

  1. skip().limit() 查询往往在 MongoDB 端变得越来越慢。随着跳过浏览文档,更多信息请参阅此处https://stackoverflow.com/a/7228190/534150

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

  3. Mongoid 方面对我来说是正确的。

【讨论】:

  • 是的,我做了一些实验,使跳过数字非常大,比如 CLI 中的 3000,这确实增加了查询时间,但仍然只有 5 毫秒。当我取出 Mongoid 范围并使用一个简单的查询条件时,我得到了一个 Moped 查询,需要 195 毫秒才能跳过 30 次。
  • 你似乎是对的。我迭代集合以构建 JSON 并一次检索一个对象。有没有办法通过跳过/限制来获得它们,执行速度要快得多?
【解决方案2】:

感谢您的想法,我认为@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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-13
    • 2013-04-23
    • 1970-01-01
    • 2021-06-23
    相关资源
    最近更新 更多