gpt4 book ai didi

sql - 为什么 Rails ActiveRecord 访问数据库两次?

转载 作者:行者123 更新时间:2023-12-04 22:32:28 25 4
gpt4 key购买 nike

@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

结果:

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)

为什么 Rails 会再次为 brokers 访问数据库,即使我已经加入/选择了他们,你知道吗?

这是模型(Broker -> Integration 是一对多关系)。请注意,这是不完整的,我只包含了建立它们关系的行

class Broker < ActiveRecord::Base

# ActiveRecord Associations
has_many :integrations

class Integration < ActiveRecord::Base

belongs_to :broker

我使用的是 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)

最佳答案

使用 include 而不是 joins 来避免重新加载 Broker 对象。

Integration.first(:conditions=>{:integration_name => params[:integration_name]}, 
:include => :broker)

没有必要提供 select 子句,因为您没有尝试规范化 brokers 表列。

注1:

在预先加载依赖项时,AR 为每个依赖项执行一个 SQL。在您的情况下,AR 将执行 main sql + broker sql。由于您试图获得一行,因此 yield 不大。当您尝试访问 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

查询返回的对象将包含 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")

关于sql - 为什么 Rails ActiveRecord 访问数据库两次?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11147942/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com