我有一个型号产品,它属于一个类别(产品表中的category_id)。我想编写一个查询,其中包含前20个产品及其类别名称。我有2种方法可以获取它:
使用includes
,如下所示:
Product.includes(:category).
order(:updated_at).
limit(20)
并在视图中取类别名称,如下所示:
<%= product.category.name if product.category %>
这将创建如下查询:
SELECT `products`.* from `products` ORDER BY `products`.updated_at LIMIT 20
SELECT `categories`.* from `categories` WHERE `categories`.id IN (1,2,3,4,5..,25)
像这样使用joins
:
Product.joins("LEFT JOIN categories ON categories.id = products.category_id").
select("products.*, categories.name as category_name").
order(:updated_at).
limit(20)
并在以下视图中使用它:
<%= product.category_name %>
这将生成如下查询:
SELECT products.*, categories.name as category_name from `products` LEFT JOIN categories ON categories.id = products.category_id ORDER BY `products`.updated_at LIMIT 20
方法1的优点是我们可以使用在Category模型上编写的模型级方法,并且代码更易于维护。但它的缺点是它使用单独的查询来查找使用IN子句的类别。
哪种方式首选?
答案 0 :(得分:2)
它不仅仅是偏好,而是性能与可维护性的问题。我会首先为你的查询提供更易维护的路线。如果您的性能开始受到某些查询的影响,请使用连接语法进行优化,或者只是从头开始编写普通的旧SQL。不要过早优化。优化您找到实际需求的位置。
答案 1 :(得分:0)
对于您的示例,我可能会选择选项1,因为它更简单,更容易阅读,并且您没有加载那么多对象,因此我认为性能损失不会太严重。
如果您可能正在加载更多数据(例如,如果您取消了limit(20)
部分),我会使用选项2,因为它可以帮助您在实例化所有需要的时候实例化Category对象他们的名字。在较小的列表中,这种开销可能可以忽略不计,但随着列表变长,它可能变得很重要。
答案 2 :(得分:0)
首选方式是您个人喜欢的方式。
尽管如此,我并没有看到使用includes
是一件大事。特别是在开发应用程序时,您在页面上的内容将会发生变化。
在我看来,在这种情况下,大部分时间都只使用includes
。除非您在行中存储了大量text
,否则您的生产和查询最终成为瓶颈,那么您应该花时间并优化它。