【问题标题】:How to prevent rails `has_many` relation joining two huge tables如何防止rails`has_many`关系加入两个大表
【发布时间】:2013-09-05 05:05:00
【问题描述】:

我正在使用 Ruby on Rails 3.1.10 开发 Web 应用程序。

目标是找到用户关注的所有用户

假设有两个模型UserFollowing

User 模型中:

has_many :following_users, :through => :followings

当调用user.following_users 时,rails help 会生成一个查询,即INNER JOIN between users and followings table 默认情况下。

users 表有超过50,000 条记录,而followings 表有超过10,000,000 条记录时,生成的内连接需要资源。

关于如何通过避免内部连接两个大表来优化性能的任何想法?

【问题讨论】:

  • 联接表是关联在 Rails 中的工作方式。你不会避免这样做(我想没有切换到 noSQL 数据库)。您的followings 表是否由user_id(或此查询中使用的任何外键)索引?正确的索引可以大大缩短查询时间。

标签: sql ruby-on-rails-3


【解决方案1】:

为避免单个查询带有内连接,您可以使用以下方法进行 2 次选择查询

# User.rb
# assuming that Following has a followed_id column for user that is being followed

def following_users_nojoin
    @following_users_nojoin ||= User.where("id IN (?)", followings.map(&:followed_id)) 
end

这不会创建连接表,但会进行两个 sql 查询。一是获取属于该用户的所有关注(除非它已经在缓存中),二是查询以查找所有关注的用户。正如评论中所建议的,关注的 user_id 索引将加快我们为用户获取所有关注的第一个查询。

如果已经检索到用户的关注,上述方法将比单个连接查询更快。

Read this 详细了解使用连接对单个查询进行多个选择查询是否更快。找出哪种方法更快的最佳方法是在生产数据库上对这两种方法进行基准测试。

【讨论】:

  • 谢谢tihom,我也有同样的想法,但是有现有的方法调用user.following_users.order("followings.id desc")在这种情况下,连接是不可避免的吗?
  • 但是当我们尝试通过followings.id 订购时,请注意followings 还没有。 :(
  • 如果这个订单是您唯一需要的,那么我们可以这样做user.following_users_nojoin.order("field(id, #{followings.reverse.map(&:followed_id).join(',')})")。这是使用已缓存的followings 并生成已关注用户 ID 的有序列表。我们同样可以在sql外使用followings来过滤记录。
  • 更新了之前的评论,因为我没有意识到你是按以下列排序的。
  • 谢谢!虽然我打算采用更通用的处理方法:P
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多