PostgreSQL ActiveRecord查询优化

问题描述 投票:0回答:1

我是RoR的新手,我需要一个返回与以下队列定义相同的实例的查询:

@all = User.all
@membersOfActivity = User.where(id: User.joins(:memberships).where("activity_id = ?", session[:current_activity_id])) 
@usersIAlreadyLiked = User.where(id: User.joins(:likes).where("activity_id = ? AND activity_likes_user IS NOT NULL", session[:current_activity_id])) 
@notWanted = @membersOfActivity + @usersIAlreadyLiked 
@queue = @all - @notWanted

但是,我理解我刚写的查询是多么低效,因为它首先下载所有用户然后选择补充。您是否知道如何提高效率并直接选择@notWanted的补充?我尝试了几个查询,但没有一个有效。如果您认为自己有更好的解决方案,请告诉我们!谢谢!

编辑:每个用户都有许多成员资格,用于将用户与活动联系起来。所以每项活动也有很多会员资格。每个成员资格都有一个user_id和一个activity_id。

每个用户都有很多喜欢,每个用户都喜欢连接用户和活动。因此每项活动也有很多喜欢。类似具有user_id,activity_id,user_liked_activity和activity_liked_user。

如果用户没有表达对活动的意见,则user_liked_activity为NULL,如果用户喜欢该活动,则为TRUE,如果用户不喜欢该活动,则为FALSE。 Viceversa for activity_liked_user。

ruby-on-rails ruby postgresql activerecord
1个回答
1
投票

这是一个使用not语法的Rails 5解决方案。乍一看,这似乎与您的原始解决方案类似,但这只运行一个查询,从单独的排他性类别(membersalready_liked)构建。

class User < ApplicationRecord
  has_many :likes
  has_many :memberships

  def self.queue(current_activity_id)
    members = User.joins(:memberships).where(memberships: {activity_id: current_activity_id})
    already_liked = User.joins(:likes).where(likes: {activity_id: current_activity_id, activity_liked_user: [true, false]})

    where.not(id: members).where.not(id: already_liked)
  end
end

您将从控制器中调用此方法,如下所示:

@queue = User.queue(session[:current_activity_id])

据我所知,对于当前的会话活动,我们需要一个查询,它将返回除属于两个类别之一的所有用户:(1)作为活动成员的用户,由具有成员关联链接的用户表示当前活动,以及(2)已经从活动中获得“喜欢”评级的用户,由具有“like”的用户表示,该用户与当前活动相关联,其中activity_likes_user为true或false(但不是nil)。

我们为每个类别建立ActiveRecord关系,但我们不会调用实际触发查询的任何内容。第1类是members,第2类是already_liked

现在我们在User模型上建立一个查询(这是隐含的,因为我们在User类的类方法中调用)要求用户id不是members之一而不是already_liked之一。

可能有更优雅的解决方案,但这确实有效,我相信它可以正确处理边缘情况,但您应该构建测试来验证这一点。

© www.soinside.com 2019 - 2024. All rights reserved.