【问题标题】:Multiple queries are executed during fetch of an associated class - ruby on rails在关联类的获取期间执行多个查询 - ruby​​ on rails
【发布时间】:2025-12-06 06:15:01
【问题描述】:

我想优化我的代码性能,而不是多个查询;在单个查询中,我可以从数据库中获取所有信息。

我的代码是这样的:

我有一个类(称为类:A),它有 STI(假设类型 A1 和类型 A2)。

还有两个与 A 类关联的类(比如说 B 类和 C 类)。

这样的……

class A < ActiveRecord::Base
    has_many :B
    has_many :C
    blahblah
end

class B < ActiveRecord::Base
    belongs_to :A

    blahblah
end

class C < ActiveRecord::Base
    belongs_to :A

    blahblah
end


class A1 < A

    blahblah
end

class A2 < A

    blahblah
end

现在,当我尝试加载 A1 时,总共执行了 9 次 查询...我们可以在 单个 查询中优化它吗??

我正在尝试执行此操作:

@datas = A1.where("id" < 5 )

控制台输出:

  A1 Columns (1.0ms)   SHOW FIELDS FROM `A`
  A1 Load (2.2ms)   SELECT * FROM `A` WHERE (id < 5) AND ( (`promotions`.`type` = 'A1' ) ) 

  C Load (0.4ms)   SELECT * FROM `C` WHERE (`C`.A_id = 1) 
  C Columns (0.7ms)   SHOW FIELDS FROM `C`
  SQL (0.1ms)   SET NAMES 'utf8'
  SQL (0.1ms)   SET SQL_AUTO_IS_NULL=0
  B Load (0.4ms)   SELECT * FROM `B` WHERE (`B`.A_id = 1) 
  B Columns (0.7ms)   SHOW FIELDS FROM `B`
Rendered blahblah (42.1ms)
  C Load (3.5ms)   SELECT * FROM `C` WHERE (`C`.A_id = 2) 
  B Load (5.3ms)   SELECT * FROM `B` WHERE (`B`.A_id = 2) 
Rendered blahblah (13.1ms)
  C Load (3.5ms)   SELECT * FROM `C` WHERE (`C`.A_id = 3) 
  B Load (5.3ms)   SELECT * FROM `B` WHERE (`B`.A_id = 3) 
Rendered blahblah (13.1ms)
  C Load (3.5ms)   SELECT * FROM `C` WHERE (`C`.A_id = 4) 
  B Load (5.3ms)   SELECT * FROM `B` WHERE (`B`.A_id = 4) 
Rendered blahblah (13.1ms)

我们能否在一个查询中从所有三个表中获取所有信息?

我的尝试

@datas = A.join(:B).join(:C).where("id" < 5)

但是得到了相同的结果......执行了多个查询而不是单个查询......

谁能帮我解决这个问题???

提前致谢。

编辑

第二次尝试:@datas= A.find(:all, :joins=&gt;[:B, :C], :conditions=&gt;"id&lt;5")

在后端,rails 执行如下:

SELECT `A`.* FROM `A` INNER JOIN `B` ON B.A_id = A.id INNER JOIN `C` ON C.A_id = A.id WHERE ( id < 5 ) AND ( (`A`.`type` = 'A1' ) )

这看起来不错。

但是当我们尝试加载 B 时(例如:&lt;%= A.B.name %&gt;)。它执行另一个查询。

所以问题仍然存在.... :(

【问题讨论】:

    标签: ruby-on-rails join has-many sti


    【解决方案1】:

    您只需将joins 替换为includes

    @datas = A.includes(:B, :C).where("id < 5")
    

    请注意,这将为包含的每个关联生成一个额外的查询。您可以通过使用joins 强制连接将其减少为一个查询

    @datas = A.joins(:B).includes(:B, :C).where("id < 5")
    

    或者您可以在其中一个关联模型上指定条件,例如

    @datas = A.includes(:B, :C).where(:B => {:column => value})
    

    【讨论】:

    • 感谢您的回答....我正在测试...一旦完成,我会通知您...
    • 你的意思是 A.includes(:B, :C).where("id
    • 你的意思是 A.joins(:B).includes(:B, :C).where("id
    • 但我得到了以下异常:NoMethodError: undefined method `includes' for #<0x7f543736a208>