Rails 7中高效获取用户关联Applicant聊天记录的优化问询
优化方案:高效获取用户的所有聊天会话(Applicant记录)
原实现的核心问题
原代码会触发N+2次数据库查询(N为用户项目数量):
- 先查询当前用户的所有项目
- 遍历每个项目时,分别查询对应Applicant记录(N次查询)
- 合并数组后再次通过ID查询Applicant
同时数组合并会额外占用内存,数据量越大性能损耗越明显。
方案1:单次SQL级联查询(最直接高效)
直接通过OR条件将两种场景(用户作为申请者、用户作为项目所有者)合并为一次数据库查询:
@chats = Applicant # 场景1:用户是申请者 .where(user_id: current_user.id) # 场景2:用户是项目所有者,关联查询对应的Applicant .or(Applicant.joins(:project).where(projects: { user_id: current_user.id })) # 按最后消息时间倒序 .order(last_message: :desc)
优势
- 仅触发1次SQL查询,彻底消除N+1问题
- 逻辑清晰,直接对应业务需求
方案2:封装User模型关联(更优雅的复用)
在User模型中定义自定义关联,把聊天会话的查询逻辑封装起来,方便后续多处调用:
class User < ApplicationRecord # ... 现有代码 ... # 定义用户的所有聊天会话关联 has_many :chat_applicants, ->(user) { where("applicants.user_id = ? OR projects.user_id = ?", user.id, user.id) .joins("LEFT JOIN projects ON projects.id = applicants.project_id") .distinct }, class_name: "Applicant" end
调用时只需一行代码:
@chats = current_user.chat_applicants.order(last_message: :desc)
补充说明
- 加入
distinct是为了预防极端场景下的重复记录(比如用户既是某项目申请者又是所有者,业务上大概率不会出现,但可以提前规避) - 关联封装后,业务代码更简洁,逻辑复用性更强
内容的提问来源于stack exchange,提问作者Frub
相关产品推荐
相关产品推荐

