通过为模型添加外键优化SQL查询及account_id空值问题解决
优化关联查询:给Sale表添加直接关联Account的字段并批量填充数据
问题背景
原本的关联结构是Account→User→Sale,查询Sale所属Account时需要经过两层关联,导致SQL查询变慢。为了优化性能,计划给Sale表直接添加account_id字段,替代通过User间接关联Account的方式。
执行初始迁移后,sales表确实新增了account_id字段,但所有记录的该字段值都是nil——原以为靠模型关联就能自动填充这个值,实际完全没生效。
初始迁移代码(这里还犯了个表名错误,写成了:bids而非:sales):
def change add_reference :bids, :account, type: :integer, after: :user_id, foreign_key: true end
原模型关联关系:
User 模型
belongs_to :account has_many :sales
Account 模型
has_many :users, dependent: :destroy has_many :sales, through: :users
Sale 模型
belongs_to :user has_one :account, through: :user
创建Sale的代码流程:
sale = Sale.new(company: item.company, sale_type: params[:sale_type]) # 中间用户校验逻辑... sale = item.place_sale!(user, params[:sale_type], params[:amount], params[:note], nil, params[:custom_amount].present?)
最终解决步骤
1. 修正迁移脚本,批量填充历史数据
新迁移脚本不仅正确添加sales表的account_id字段,还通过原生SQL批量更新已有数据,把User关联的Account ID同步到Sale记录里:
def change add_reference :sales, :account, type: :integer, after: :user_id, foreign_key: {on_delete: :nullify}, index: true reversible do |dir| dir.up do ActiveRecord::Base.connection.execute("UPDATE sales JOIN users ON sales.user_id = users.id SET sales.account_id = users.account_id;") end end end
这里做了几个关键调整:
- 修正了初始迁移的表名错误,把
:bids改为:sales - 给
account_id添加索引,提升后续查询性能 - 外键设置
on_delete: :nullify,避免Account被删除时连带删除关联的Sale
2. 更新模型关联关系
移除原来的间接关联,改成Sale与Account直接关联:
修改后的 Sale 模型
belongs_to :user belongs_to :account # 新增直接关联
修改后的 Account 模型
has_many :users, dependent: :destroy has_many :sales # 移除through: :users,改为直接关联
3. 确保新创建的Sale自动填充account_id
为了避免新创建的Sale再出现account_id为nil的情况,可以在创建逻辑里手动赋值,或者给Sale模型加回调:
- 方式一:在
place_sale!方法内部赋值
# 在place_sale!创建Sale的逻辑中 sale.account_id = user.account_id
- 方式二:给Sale模型添加回调
class Sale < ApplicationRecord belongs_to :user belongs_to :account before_save :set_account_id_from_user private def set_account_id_from_user self.account_id ||= user&.account_id end end
内容的提问来源于stack exchange,提问作者slime_saw
相关产品推荐
相关产品推荐

