优化 ActiveRecord 查询
Posted
技术标签:
【中文标题】优化 ActiveRecord 查询【英文标题】:Optimizing an ActiveRecord query 【发布时间】:2015-11-25 11:57:10 【问题描述】:我有以下模型,并希望获取特定用户尚未在其上点赞的所有可用帖子。
后模型:
class Post < ActiveRecord::Base
has_many :likes
has_many :users, through: :likes
scope :available, -> where available: true
end
喜欢模特:
class Like < ActiveRecord::Base
belongs_to :post
belongs_to :user
end
用户模型:
class User < ActiveRecord::Base
has_many :likes
has_many :posts, through: :likes
end
我想出了这个 ActiveRecord 查询:
Post.available - Post.available.joins(:likes).where('likes.user_id = ?', user.id)
有没有优化的方法来实现这一点?甚至可能是等效的 SQL 查询?
【问题讨论】:
创建Post.available.joins(:likes).where('likes.user_id = ?', user.id)
的范围,然后减去
【参考方案1】:
这可以通过以下方式实现:
Post.available.where("id not in (select post_id from likes where user_id = ?)", user.id)
【讨论】:
【参考方案2】:我猜这可以做到:
Post.available.where( 'NOT EXISTS (?)',
user.likes.where('likes.post_id = posts.id')
)
您也可以完全不使用 SQL 字符串来执行此操作,如下所示:
Post.available.where(
user.likes.where(post_id: Post.arel_table[:id]).exists.not
)
但我已经看到像这样的构造会导致参数绑定出现问题。我很确定这是一个错误,但我不确定这个技巧是否存在于公共 ActiveRecord API 中(ActiveRecord/Arel 真的应该受到责备)。
【讨论】:
【参考方案3】:试试这个:-
Post.available.joins(:likes).where('likes.user_id NOT IN (?)', user.id)
或者您可以在后期模型中添加范围
class Post < ActiveRecord::Base
scope :no_user_likes, ->(id) joins(:likes).where('likes.user_id NOT IN (?)', id)
end
然后你可以这样调用:-
Post.available.no_user_likes(user.id)
【讨论】:
与(现已正确删除)第一个答案的问题相同:这会获取 除此用户之外的所有人 喜欢的帖子。所以最终结果是错误的。以上是关于优化 ActiveRecord 查询的主要内容,如果未能解决你的问题,请参考以下文章
使用过滤器对 Active Record 对象进行分页的优化方法是啥?
动态 Active Record 查询中的 Codeigniter 括号
CodeIgniter Active Record 查询 WITH/ 子查询
Rails 和 Active Record:复杂的 SQL 查询
如何在 Active Record 迁移中为字段添加索引以加快查询速度?
SQL 基准测试:PHP ActiveRecord ORM 与 MySQL 与 CodeIgniter Active Record 与标准 PHP