ActiveRecord / SQL有条件地包括关联模型而不加入

时间:2017-05-22 14:34:11

标签: sql ruby-on-rails activerecord

在我的RequestsController#index我有一个简单的查询返回47行(实际查询包含一堆其他相关和条件,这里没有相关性):

requests = current_contact.requests.includes(:hub_post).limit(20)

我有以下型号:

class HubPost < ApplicationRecord
    belongs_to :contact
    has_many :requests, dependent: :destroy
end

class Request < ApplicationRecord
    belongs_to :contact
    belongs_to :hub_post, optional: true
end

在HubPost中,我有以下方法:

def shared_by(count=2, excluded=nil)
    ids = Request.where(hub_post_id: self.id, completed: true).pluck(:contact_id)
    ids = ids.keep_if { |id| id != excluded.id } if excluded.present?
    ActiveModel::Serializer::CollectionSerializer.new(Contact.where(id: ids).limit(count), serializer: PortalContactSerializer).as_json.shuffle
end

def shared_by_count(excluded=nil)
    ids = Request.where(hub_post_id: self.id, completed: true).pluck(:contact_id)
    ids = ids.keep_if { |id| id != excluded.id } if excluded.present?
    Contact.where(id: ids).count
end

在目前的形式中,此代码代表了一个非常严重的N + 1问题。此端点平均需要2,000毫秒才能响应。现在,我可以通过将.includes(:hub_post)更改为.includes(hub_post: [requests: [:contact]])来轻松解决N + 1问题。现在的问题是这个查询从数据库中提取了数千个请求行,并将它们作为ActiveRecord对象在内存中实例化,这是一个更糟糕的问题。

理想情况下,我只想包含completed = truecontact_id != current_contact.id的请求,并且我希望limit {包含的行数>到2或count定义使我不会抓取数千条记录。

为了使事情变得更复杂,我不想join关联,因为我放弃了一些请求。我想获取所有current_contact的请求,即使该请求没有hub_post或者它有一个但hub_post没有任何其他请求。

我尝试将includeswhere语句和references语句一起使用,但这似乎只是在进行连接,如下所示。当我希望它返回全部47行时,此查询仅返回18行。

requests.includes(hub_post: [:requests]).where(hub_post: { requests: { completed: true } }).references(hub_post: [:requests])

据我所知,includes无法通过我在该主题上看到的其他问题有条件地判断一个关联。我想知道的是,是否有可能以高效的方式解决N + 1问题而不会导致内存消耗问题。

0 个答案:

没有答案