Mysql N+;1视图错误
我认为导致这个N+1错误的原因是,由于视图必须呈现集合,因此每个状态更新都需要进行查询调用,以便显示它相对于其他状态更新的变量 这导致了大量的查询。如何使所有这些状态更新一次可用,并从status update类中调用数组来进行这些计算,而不是每次都访问数据库 我可能会错过一些东西,所以任何洞察都会很棒!我尝试过使用include和大约100个其他东西来更改查询调用 这是bullet给我的错误信息:Mysql N+;1视图错误,mysql,ruby,ruby-on-rails-3,ruby-on-rails-4,Mysql,Ruby,Ruby On Rails 3,Ruby On Rails 4,我认为导致这个N+1错误的原因是,由于视图必须呈现集合,因此每个状态更新都需要进行查询调用,以便显示它相对于其他状态更新的变量 这导致了大量的查询。如何使所有这些状态更新一次可用,并从status update类中调用数组来进行这些计算,而不是每次都访问数据库 我可能会错过一些东西,所以任何洞察都会很棒!我尝试过使用include和大约100个其他东西来更改查询调用 这是bullet给我的错误信息: user: Pablo N+1 Query detected StatusUpdate =&
user: Pablo
N+1 Query detected
StatusUpdate => [:client]
Add to your finder: :include => [:client]
N+1 Query method call stack
/Users/Nick/Code/Rails/gj/app/models/status_update.rb:27:in `prev'
/Users/Nick/Code/Rails/gj/app/models/status_update.rb:36:in `weight_change'
/Users/Nick/Code/Rails/gj/app/models/client.rb:11:in `weight_change'
/Users/Nick/Code/Rails/gj/app/views/status_updates/show.html.erb:39:in `_app_views_status_updates_show_html_erb__176120213182464780_70358939483460'
status_updates.rb
def prev
prev = self.client.status_updates.where("created_at < ?", self.created_at)[-1]
if prev == nil
prev = self
else
prev
end
end
def weight_change
weight_change = prev.total_weight - total_weight
cut weight_change
end
状态更新控制器#显示
show.html
<% if @status_updates != nil %>
<%= render(partial: "status_updates", collection: @status_updates) %>
<% else %>
<p style="text-align:center">No status updates yet.</p>
<% end %>
还没有状态更新
_status_updates.html
<tr>
<td class="left"><%= status_updates.entry_date.strftime("%m/%d/%y") %></td>
<td class="left phase"><%= status_updates.phase %> <a href="#">+</a></td>
<td><%= status_updates.total_weight %></td>
<td><%= status_updates.weight_change %></td>
<td><%= status_updates.lbm_weight %></td>
<td><%= status_updates.lbm_change %></td>
<td><%= status_updates.total_lbm_change %></td>
<td><%= BigDecimal(status_updates.body_fat_pct * 100, 5)%>%</td>
<td><%= status_updates.fat_change %></td>
<td><%= status_updates.total_fat_change %></td>
<td><%= link_to('×'.html_safe, status_updates, method: :delete) %></td>
</tr>
%
client.rb
def weight_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.weight_change
end
end
class Client < ActiveRecord::Base
belongs_to :trainer
has_many :status_updates
validates :firstname, :lastname, presence: true
def weight_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.weight_change
end
end
def fat_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.fat_change
end
end
def lbm_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.lbm_change
end
end
def bfp_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.bfp_change
end
end
def total_weight_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.total_weight_change
end
end
end
class客户端
我建议不要每次阅读状态更新时都计算权重变化
,而应该在自己的列中写入状态更新时计算它(权重变化
)
这种读取记录的方法是直接的,不需要任何循环回到旧记录。为什么不在创建记录时将权重更改保存到状态更新中呢?显示状态更新的内容,而不是使用某些数组[-1]
,最好使用some_array.last
如果只是为了清楚起见。好的,我编辑了这个问题,包括了部分调用和部分调用的模型调用,这样你就可以更全面地了解发生了什么。@UriAgassi我明白了。因此,与每次调用状态更新时搜索此信息不同,我可以在创建状态更新时将信息保存到每个状态更新中,因此我只在每个状态更新中调用信息,因为该信息与其他信息相关。
class Client < ActiveRecord::Base
belongs_to :trainer
has_many :status_updates
validates :firstname, :lastname, presence: true
def weight_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.weight_change
end
end
def fat_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.fat_change
end
end
def lbm_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.lbm_change
end
end
def bfp_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.bfp_change
end
end
def total_weight_change(stat_present)
if stat_present == false
0
elsif stat_present == true
self.status_updates.reverse.first.total_weight_change
end
end
end