【问题标题】:Rails 3 Applying limit and offset to subqueryRails 3 将限制和偏移量应用于子查询
【发布时间】:2012-10-30 06:07:08
【问题描述】:

我有一个类似这样的查询(在 song.rb 中):

def self.new_songs
  Song.where(id: Song.grouped_order_published).select_important_stuff
end

稍后在我的应用程序中,它会通过限制和偏移量,让我们在控制器中说:

@songs = Song.new_songs.limit(10).offset(10)

我的应用程序的结构方式,我想保留这种设置方法,但不幸的是它真的很慢,因为它限制了外部查询而不是子查询。

有没有办法可以公开子查询,使其接收限制和偏移量而不是外部查询?

编辑:我应该添加我正在使用 postgres 9.2。

编辑 2:我想以这种方式执行此操作的原因是我正在进行分页,我需要获取总行数的“计数”。所以我做了这样的事情:

@songs = Song.new_songs
...
@pages = @songs.count / 10
...
render @songs.limit(params[:page]).offset(0)

如果我要以某种方式更改它,我将不得不完全重做(在很多地方)。通过在实际调用它之前不限制它,我可以在两者之间进行计数,然后在最后只获取页面。我想我正在寻找更多关于如何使用内部查询完成此操作的建议,而不会随着数据库的增长而变得非常缓慢。

【问题讨论】:

  • 所以我通过不做子查询来解决这个问题。不过,这仍然是一个有趣的问题。
  • 所以问题是您需要知道匹配的总数并获得 10 个切片,但您不想运行两次查询,对吧?当然,您不希望更改的代码超出您的需要。

标签: sql ruby-on-rails-3 postgresql activerecord subquery


【解决方案1】:

我无法尝试该解决方案,而且我也不是 ruby​​ 专家,但据我了解,您需要一个对象,该对象将所有方法调用传递给完整查询,但将限制和偏移量传递到完整查询并存储有限的 sub_query同时。

它可能看起来像这样:

class LimitedSubquery < Object

  # sub_query has to be stored so we can limit/offset it
  def initialize(sub_query)
    @sub_query = sub_query
  end

  # Make sure everybody knows we can be used like a query
  def self.respond_to?(symbol, include_private=false)
     super || full_query.respond_to?(symbol, include_private)
  end

  # Missing methods are probably meant to be called on the whole query
  def self.method_missing(method_sym, *arguments, &block)
    if full_query.respond_to?(method_sym)
      full_query.send(method_sym, *arguments, &block)
    else
      super
    end
  end

  # Generate the query for execution
  def self.full_query
    Song.where(id: @sub_query).select_important_stuff
  end

  # Apply limit to sub_query
  def self.limit(*number)
    LimitedSubquery.new(@sub_query.limit(*number))
  end

  # Apply offset to sub_query
  def self.offset(*number)
    LimitedSubquery.new(@sub_query.offset(*number))
  end
end

比这样称呼它

def new_songs
  LimitedSubquery.new(Song.grouped_order_published)
end

如果我有什么问题,请编辑我!

问候

TC

【讨论】:

  • 没查出来,但是逻辑是合理的。我最终找到了避免子查询的方法,但你应该得到积分。
  • 谢谢!原始查询似乎可以重写,但正如您在评论中所述,您希望找到原始问题的解决方案。
【解决方案2】:

您应该考虑使用will_paginate gem。这让您远离手动计算所有这些的麻烦;-)

【讨论】:

  • 我不明白你的评论。据我了解,您正在寻找分页。如果不是,请澄清您的问题。谢谢你。另一种方法是为 new_songs 方法提供两个参数 limit 和 offset,然后将它们用于 def self.new_songs(limit, offset) Song.where(id: Song.grouped_order_published.limit(limit).offset(offset)).select_important_stuff调用@songs = Song.new_songs.limit(10).offset(10) 根本不起作用。
  • 我觉得已经够清楚了。如果您想查看真正解决我问题的答案,请查看所选答案。
  • 很高兴您现在有解决问题的方法!
猜你喜欢
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2019-06-06
  • 2016-09-19
  • 1970-01-01
  • 2012-05-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多