找到连接表中不存在的随机项并且不重复先前随机项的最有效方法

时间:2016-05-26 01:24:20

标签: sql ruby-on-rails random rails-activerecord

在我的Rails 4应用程序中,我有一个Item模型和一个Flag模型。项目has_many标志。标志belong_to项目。标记具有item_iduser_idreason属性。我正在使用enum作为待处理状态。我需要最有效的方法来获取flags表中不存在的项,因为我有一个非常大的表。我还需要确保当用户点击生成另一个随机项时,它不会重复当前的随机项。之后可以随时重复,只是不要背靠背。

这是我到目前为止所做的:

def pending_item
  @pending_items = Item.joins("LEFT OUTER JOIN flags ON flags.item_id = items.id").
                   where("items.user_id != #{current_user.id} and flags.id is null")
  @pending_item = @pending_badges.offset(rand @pending_badges.count).first
end

有比这更有效的方式吗?

我怎样才能确保同一pending_item没有背靠背重复?

1 个答案:

答案 0 :(得分:1)

你所拥有的是在我所知道的数据库中最快的方式(这就是为什么我给它here)。许多其他Stack Overflow帖子讨论了从表中有效选择随机行的方法;如果您从整个表格中进行选择,则可以使用更有效的方法,但是当您从查询中选择随机结果时,这些方法不适用。

如果性能至关重要,那么在内存中执行它会快得多。

  • 首次需要为给定用户选择随机待处理项时,从数据库中选择所有用户的待处理项并将其存储在Rails缓存中。 (这仅适用于每个用户有合理数量的待处理项目。)
  • 每次您需要为给定用户选择随机待处理项目时,请从缓存中获取完整列表,然后选择.sample或其他随机成员。
  • 这里有一个棘手的部分:保持缓存一致,每次你做任何可以改变用户的待处理项目的完整列表(包括添加新的标志类型)时,你和# 39; ll需要使缓存条目无效。

这需要付出很多努力,所以你真的不得不这样做。

关于避免重复,可靠地执行此操作的唯一方法是存储显示的最后一个待处理项目并将其从查询中排除

def pending_item
  @pending_items = UserItem.
    joins("LEFT OUTER JOIN flags ON flags.item_id = items.id").
    where("items.user_id != ?", current_user.id).
    where("flags.id is null").
    where("items.id != ?", previous_shown_item_id)
  @pending_item = @pending_badges.offset(rand @pending_badges.count).first
end

或者,如果您在内存中进行随机选择,请在执行此操作时排除最后显示的待处理项目。