Ruby on rails 使用实例变量进行缓存会降低性能
下面的所有示例都会调用Ruby on rails 使用实例变量进行缓存会降低性能,ruby-on-rails,performance,Ruby On Rails,Performance,下面的所有示例都会调用pending\u通知?和reviewable\u通知 对于用户,我有以下一组实例方法: def pending_notifications? return true if reviewable_notifications.size > 0 end def reviewable_notifications @reviewable_notifications ||= self.employee.notifications.where(read: [nil, f
pending\u通知?
和reviewable\u通知
对于用户
,我有以下一组实例方法:
def pending_notifications?
return true if reviewable_notifications.size > 0
end
def reviewable_notifications
@reviewable_notifications ||= self.employee.notifications.where(read: [nil, false])
end
视图按以下方式使用它们:
<% if current_user.pending_notifications? %>
<li><%= link_to fa_icon("envelope") + " #{current_user.reviewable_notifications.count} Notification(s)", user_notifications_path(id: current_user.id) %></li>
<% else %>
<li><%= link_to fa_icon("inbox") + " Notification Center", user_notifications_path(id: current_user.id) %></li>
<% end %>
这很好,但在重构之前,我没有使用推荐的缓存实例变量的技术,但在分析中得到了完全相同的查询。此外,它始终以20毫秒以下的速度运行。下面是代码最初是如何编写的。为什么Rails不调用同一个查询两次?为什么用这种方式编写的代码性能更好
def pending_notifications?
return true if self.employee.notifications.where(read: [nil, false]).size > 0
end
def reviewable_notifications
self.employee.notifications.where(read: [nil, false])
end
差异不基于正在生成的查询…
如果你使用
`@reviewable_notifications ||= self.employee.notifications.where(read: [nil, false])`
只要@reviewable\u notifications
为零,您将只点击数据库
当它获取一个值时,它将被使用
作为一个简单的示例,您可以在控制台中编写:
2.1.2 :001 > 5.times { User.first } # no caching, hit 5 times your DB
User Load (0.2ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5
2.1.2 :002 > 5.times { @user ||= User.first } # caching, only 1 hit
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5
当然,mysql有自己的查询缓存,因此如果同一个查询访问数据库,可能会从数据库查询缓存返回结果(在上面的示例中,您可以看到最后一个查询比第一个查询花费的时间更少,这可能是因为mysq从其缓存提供结果)只有在Ruby中进行了昂贵的计算,并且您在多个地方使用了该值时,才需要记住这样的值 这种特殊的计算是在SQL中进行的,Rails在默认情况下已经缓存了DB查询,所以您没有看到任何更改
2.1.2 :001 > 5.times { User.first } # no caching, hit 5 times your DB
User Load (0.2ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5
2.1.2 :002 > 5.times { @user ||= User.first } # caching, only 1 hit
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5