以下所有示例都会同时调用pending_notifications?
和reviewable_notifications
我为User
提供了以下一组实例方法:
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 %>
当我分析负载时,正在调用一个查询:
SELECT COUNT(*) FROM "notifications" WHERE "notifications"."employee_id" = ? AND (("notifications"."read" = 'f' OR "notifications"."read" IS NULL))
这很好,但在我的重构之前,我没有使用推荐的缓存技术和实例变量,但我在分析中得到了完全相同的查询。此外,它一直运行在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
答案 0 :(得分:1)
记住这样的值只有在Ruby中进行昂贵的计算并且在多个地方使用该值时才有用。
此特定计算发生在SQL中,Rails默认已缓存数据库查询,因此您没有看到任何更改。
答案 1 :(得分:0)
差异不是基于正在生成的查询...
如果你使用
`@reviewable_notifications ||= self.employee.notifications.where(read: [nil, false])`
只要@reviewable_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服务于其缓存的结果)