1

我有一个模型产品,它属于一个类别(产品表中的类别 ID)。我想编写一个查询,其中包含前 20 个产品及其类别名称。我有两种获取方式:

  1. 使用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)
    
  2. 像这样使用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 子句的类别。

哪个是首选方式?

4

3 回答 3

2

它不仅仅是偏好,而是性能与可维护性的问题。我会首先为您的查询采用更易于维护的路线。如果某些查询的性能开始受到影响,请使用连接语法进行优化,或者从头开始编写普通的旧 sql。不要过早优化。优化您发现实际需求的地方。

于 2012-04-08T04:17:31.987 回答
0

对于您的示例,我可能会选择选项 1,因为它更简单、更易于阅读,而且您没有加载那么多对象,所以我认为性能影响不会太严重。

在您可能要加载更多数据的情况下(例如,如果您取下limit(20)零件),我会选择选项 2,因为当您只需要它们的名称时,它可以避免实例化 Category 对象。在较小的列表中,这种开销可能可以忽略不计,但随着列表变长,它会变得很重要。

于 2012-04-07T19:23:31.710 回答
0

首选方式是您个人喜欢的方式。

不过老实说,我不认为使用 anincludes有什么大不了的。特别是在开发应用程序时,您在页面上放置的内容将会发生变化。

在我看来,只是includes在这种情况下使用大部分时间。除非您在行中存储了大量数据,text或者您开始​​生产并且该查询最终成为瓶颈,否则您可能应该花时间优化它。

于 2012-04-08T01:47:01.040 回答