关联后跟命名范围会产生重复的 SQL 查询
我在工作中遇到了这个奇怪的问题,因此我创建了一个最小的应用程序来突出显示该问题。我有两个具有简单关联的模型:
class Parent < ActiveRecord::Base
has_many :children
end
和
class Child < ActiveRecord::Base
belongs_to :parent
named_scope :only_adults, :conditions => "adult is true"
end
现在,当我这样做时,
p = Parent.first
p.children.only_adults.all()
我希望 Rails 生成包含所有条件的单个 SQL 查询。但是,这是我在日志中看到的内容:
Child Load (0.5ms) SELECT * FROM "children" WHERE ("children".parent_id = 1)
Child Load (0.3ms) SELECT * FROM "children" WHERE ("children".parent_id = 1) AND ((adult is true) AND ("children".parent_id = 1))
第一个查询基本上是无用的,并且在大型集合的情况下可能非常耗时。
有谁知道为什么 Rails 会这样?
没有执行
p.children.only_adults.all()
请注意,我
Child.by_parent(p.id).only_adults.all()
where by_parent
是命名范围的操作,而是只得到一个查询。
另请注意 Parent_id 条件的重复。这没什么大不了的。
感谢您的反馈。
I came across this strange issue at work so I created a minimal app to highlight the problem. I have two models with a simple association:
class Parent < ActiveRecord::Base
has_many :children
end
and
class Child < ActiveRecord::Base
belongs_to :parent
named_scope :only_adults, :conditions => "adult is true"
end
Now when I do
p = Parent.first
p.children.only_adults.all()
I would expect rails to generate a single SQL query containing all the conditions. However, here's what I see in the log:
Child Load (0.5ms) SELECT * FROM "children" WHERE ("children".parent_id = 1)
Child Load (0.3ms) SELECT * FROM "children" WHERE ("children".parent_id = 1) AND ((adult is true) AND ("children".parent_id = 1))
The first query is basically useless and can be very time-comsuming in the case of large collections.
Does anyone have an idea why rails is behaving as such?
Note that instead of doing
p.children.only_adults.all()
I do
Child.by_parent(p.id).only_adults.all()
where by_parent
is a named scope, then I get only one query.
Also note the duplication of the parent_id condition. This is not a big deal.
Thank you for your feedback.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
原因与 Rails 2.3.x(而不是 Rails 3.0.x)中执行查询的方式有关。在 Rails 2 中,调用 p.children 将自动执行查询,无论您附加到查询其余部分的命名范围如何。解决这个问题的唯一方法是组合使用named_scopes,就像您在“Child.by_parent(p.id).only_adults.all()”中所做的那样,因为命名范围保留了推迟查询的行为。在 Rails 3 中,查询会一直构建,直到找到执行关键字(count、all、first、last),因此可以在单个查询中执行以下操作:
The reason has to do with the way queries are executed in Rails 2.3.x, as opposed to Rails 3.0.x. In Rails 2, calling p.children will automatically execute the query, regardless of the named scopes you have attached to the rest of the query. The only way to get around this is to use named_scopes in combination, like you do in "Child.by_parent(p.id).only_adults.all()" since the named scopes keep this behavior of postponing the query. In Rails 3 the query is built up until an execute keyword is found (count, all, first, last), so it's possible to do the following in a single query: