bgc*_*ode 2 sql activerecord ruby-on-rails
@integration = Integration.first(:conditions=> {:integration_name => params[:integration_name]}, :joins => :broker, :select => ['`integrations`.*, `brokers`.*'])
$stderr.puts @integration.broker.id # This line causes Brokers to be queried again
Run Code Online (Sandbox Code Playgroud)
结果是:
Integration Load (0.4ms) SELECT `integrations`.*, `brokers`.* FROM `integrations` INNER JOIN `brokers` ON `brokers`.id = `integrations`.broker_id WHERE (`integrations`.`integration_name` = 'chicke') LIMIT 1
Integration Columns (1.5ms) SHOW FIELDS FROM `integrations`
Broker Columns (1.6ms) SHOW FIELDS FROM `brokers`
Broker Load (0.3ms) SELECT * FROM `brokers` WHERE (`brokers`.`id` = 1)
Run Code Online (Sandbox Code Playgroud)
任何想法为什么Rails会再次击中数据库,brokers即使我已经加入/选择它们?
以下是模型(Broker - > Integration是1对多关系).请注意,这是不完整的,我只包括建立关系的行
class Broker < ActiveRecord::Base
# ActiveRecord Associations
has_many :integrations
class Integration < ActiveRecord::Base
belongs_to :broker
Run Code Online (Sandbox Code Playgroud)
我正在使用Rails/ActiveRecord 2.3.14,所以请记住这一点.
当我做Integration.first(:conditions=> {:integration_name => params[:integration_name]}, :include => :broker)那条线导致两个SELECTs
Integration Load (0.6ms) SELECT * FROM `integrations` WHERE (`integrations`.`integration_name` = 'chicke') LIMIT 1
Integration Columns (2.4ms) SHOW FIELDS FROM `integrations`
Broker Columns (1.9ms) SHOW FIELDS FROM `brokers`
Broker Load (0.3ms) SELECT * FROM `brokers` WHERE (`brokers`.`id` = 1)
Run Code Online (Sandbox Code Playgroud)
使用include而不是joins避免重新加载Broker对象.
Integration.first(:conditions=>{:integration_name => params[:integration_name]},
:include => :broker)
Run Code Online (Sandbox Code Playgroud)
select由于您没有尝试规范化brokers表列,因此无需提供该子句.
注1:
在急切加载依赖项时,AR每个依赖项执行一个SQL.在你的情况下,AR将执行主sql + brokersql.既然你试图获得一排就没有多少收益.当您尝试访问N行时,如果您急切加载依赖项,则将避免N + 1问题.
笔记2:
在某些情况下,使用自定义预先加载策略可能是有益的.我们假设您只想获取集成的关联代理名称.您可以按如下方式优化您的sql:
integration = Integration.first(
:select => "integrations.*, brokers.name broker_name",
:conditions=>{:integration_name => params[:integration_name]},
:joins => :broker)
integration.broker_name # prints the broker name
Run Code Online (Sandbox Code Playgroud)
查询返回的对象将包含select子句中的所有别名列.
当您想要返回Integration对象时,即使没有相应的Broker对象,上述解决方案也不起作用.你必须使用OUTER JOIN.
integration = Integration.first(
:select => "integrations.*, brokers.name broker_name",
:conditions=>{:integration_name => params[:integration_name]},
:joins => "LEFT OUTER JOIN brokers ON brokers.integration_id = integrations.id")
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1279 次 |
| 最近记录: |