我目前有以下型号:MinorCategory>产品>评论 在视图中,我显示了评论最多的12个MinorCategories。这个视图的响应速度很慢,我认为这是我查询的一个问题。
这是我目前的代码:
class MinorCategory < ActiveRecord::Base
has_many :products
has_many :reviews, through: :products
...
def count_reviews
self.reviews.count
end
...
end
class Review < ActiveRecord::Base
belongs_to :product, touch: true
...
end
class HomeController < ApplicationController
@categories = MinorCategory.all.sort_by(&:count_reviews).reverse.take(12)
end
基本上就是这样。在视图中我会浏览每个@categories并显示一些内容,但控制器中的查询似乎很慢。来自SkyLight:
SELECT COUNT(*)FROM“review”INNER JOIN“products”ON“review”。“product_id”=“products”。“id”WHERE“products”。“minor_category_id”=? ...平均472ms
我对sql或活动记录不太满意,对Ruby on Rails来说还不是很新。我花了几个小时尝试其他方法,但我无法让它们工作,所以我想我会在这里查看。
提前感谢任何有片刻的人。
答案 0 :(得分:0)
您需要一些基本的SQL知识才能更好地了解数据库查询的工作方式,以及如何利用DBMS。使用ActiveRecord
不是不学习SQL的借口。
也就是说,您的查询效率非常低,因为您根本不会使用数据库的强大功能。在Ruby环境和数据库环境中浪费资源。
唯一的数据库查询是
MinorCategory.all
提取所有记录。这是非常昂贵的,特别是如果你有大量的类别。
此外,self.reviews.count
效率很低,因为它受N+1 query issue的影响。
最后但并非最不重要的是,排序和限制是在Ruby环境中进行的,而您应该在数据库中进行排序和限制。
您可以通过利用数据库计算功能轻松获得更有效的查询。您需要将两个表连接在一起。查询应如下所示:
SELECT
minor_categories.*, COUNT(reviews.id) AS reviews_count
FROM
"minor_categories" INNER JOIN "reviews" ON "reviews"."minor_category_id" = "minor_categories"."id"
GROUP BY
minor_categories.id
ORDER BY
reviews_count DESC
LIMIT 10
在ActiveRecord中转换为
categories = MinorCategory.select('minor_categories.*, COUNT(reviews.id) AS reviews_count').joins(:reviews).order('reviews_count DESC').group('minor_categories.id').limit(10)
您可以使用reviews_count
# take a category
category = categories[0]
category.reviews_count
另一种不需要JOIN的方法是将计数器缓存在类别表中。