我有一个'课程'具有以下属性的模型;
Course
Price - float
Featured - boolean
我的问题如下,我需要控制器中的4个列表,最近的课程,付费课程,免费课程和特色课程。
按照以下方式编写控制器是个好习惯吗?
def index
@courses = Course.order(created_at: :desc)
@free_courses = []
@courses.map {|c| @free_courses << c if c.price == 0}
@premium_courses = []
@courses.map {|c| @premium_courses << c if c.price> 0}
@featured_courses = []
@courses.map {|c| @featured_courses << c if c.featured}
end
或单独进行咨询?
def index
@courses = Course.order(created_at: :desc)
@free_courses = Course.where("price == 0")
@premium_courses = Course.where("price > 0")
@featured_courses = Course.where(featured: true)
end
我查看了日志,第一个选项更具性能,但我怀疑它是否是反对伙伴。
谢谢大家!
答案 0 :(得分:2)
随着Course表的大小增加,第二种方法将比第一种方法更快。第一种方法必须迭代表中的每条记录4次。第二种方法只创建一个与where子句匹配的记录的关系,因此它的工作量较少。
此外,第二种方法具有懒惰的优点。每个查询仅在使用时运行,因此可以沿代码路径进一步更改。它更灵活。
请注意,对于在处理逻辑的Course模型上创建范围的第二种方法,这将是一种改进。例如,课程,免费课程,高级课程和特色课程各一个。这样做的好处是可以将数据库逻辑放在模型中而不是控制器中,从而可以更容易地重用和维护数据库逻辑。
答案 1 :(得分:1)
第二种方法更好,因为当您使用.where()方法时,您将在数据库本身而不是控制器中安排查询。
答案 2 :(得分:0)
通常不好的做法是在Rails(即Course.map
或Course.all
)中迭代数据库中的所有记录,以提高性能和内存使用率。随着数据库的增长,这会成为指数级问题。使用Course.where()
方法要好得多。您可能需要默认的排序顺序,因此您可以在模型中添加一行。
default_scope { order(created_at: :desc) }
然后你可以在控制器中执行此操作,默认情况下他们会进行排序:
@courses = Course.all
我还建议在您的模型中添加范围,以便于访问。 所以在你的course.rb文件中
scope :free -> { where("price == 0") }
scope :premium -> { where("price > 0") }
scope :featured -> { where(featured: true) }
然后在您的控制器中,您可以这样做:
@courses = Course.all
@free_courses = Course.free
@premium_courses = Course.premium
@featured_courses = Course.featured
如果您需要将这些范围组合起来,也可以链接这些范围,以便您可以执行以下操作:
@mixed_courses = Course.premium.featured
正如其他人所解释的那样,Model.where()
通过在where("Write Pure SQL QUERIES HERE")
内传递sql来执行数据选择,其中常规ruby可枚举方法(.map
)迭代数组,必须将其实例化为ruby对象。这就是内存/性能问题受到重创的地方。如果您正在使用小型数据集,那就没关系了,但任何有数据量的内容都会变得很难看。