我目前正在进入一个 Ruby on Rails 项目,我实际上并没有任何经验。现在,我们遇到了一些我认为与执行过多查询有关的性能问题。
我们在 Controller 中设置了一个 Service
模型,如下所示:
@services = Service.includes(:points).with_points
with_points
范围在服务中定义如下:scope :with_points, -> { joins(:points).where.not(points: []).distinct }
(我认为这里不需要 where 子句,但这可能与问题无关。)
然后在 View 中,我们使用获取的服务,带有链接点,如下所示:
<% @services.each do |s| %>
<div class="col-xs-12 col-sm-6 col-lg-4 serviceDiv" data-rating="<%= s.service_ratings %>" >
<% if s.service_ratings == "A" %>
<% grade = "rating-a" %>
<!-- etc. -->
现在,就我在研究时所见,当尝试列出表中的所有行时,这是一种相对正常的模式。但是,当我查看日志时,似乎对每个服务都执行了单独的查询?
# This query is what I'd expect:
SQL (1.6ms) SELECT DISTINCT "services"."id" # etc, etc
# But then we also get one of these for every service
Service Exists (1.5ms) SELECT 1 AS one FROM "services" WHERE "services"."name" = $1 AND ("services"."id" != $2) LIMIT $3
# And quite a few of these for every service:
CACHE Service Exists (0.0ms) SELECT 1 AS one FROM "services" WHERE "services"."name" = $1 AND ("services"."id" != $2) LIMIT $3
现在,我的预感是那些“存在服务”的台词是坏消息。它们是什么,它们来自哪里?还有什么我在这里遗漏的相关内容吗?
最佳答案
在@MarekLipka 在对这个问题的评论中提出了一些建议后,我设法找到了问题的根源。不确定将来有多少人会遇到这种设置,但我会分享以防万一。
线索是在我们访问 s.service_ratings
中,它实际上不是数据库中的一列。 ActiveRecord Query Trace 指出所有这些查询的来源是 View 中对 s.service_ratings
的引用,这是一个危险信号。service_ratings
实际上是 Service
模型上的一种方法(假设我在这里使用了正确的术语),除了基于对模型的几个属性的计算返回一个值之外,也称为 self.update_attributes
以实际将该值存储在数据库中。这意味着每次我们检索该模型的数据以显示它时,我们还会运行另一个查询以将该值保存到数据库中 - 通常是冗余的。
换句话说,我们现在的解决方案是要么在其他时间点运行计算并将其存储在数据库中一次,要么在我们每次需要时重新计算并且根本不存储它。
关于ruby-on-rails - 为什么 Ruby on Rails 执行 `SELECT 1 AS one` 查询?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50483971/