哪个是首选,:include或:join?

时间:2012-04-07 19:11:13

标签: mysql ruby-on-rails ruby-on-rails-3 activerecord

我有一个型号产品,它属于一个类别(产品表中的category_id)。我想编写一个查询,其中包含前20个产品及其类别名称。我有2种方法可以获取它:

  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
    
  3. 方法1的优点是我们可以使用在Category模型上编写的模型级方法,并且代码更易于维护。但它的缺点是它使用单独的查询来查找使用IN子句的类别。

    哪种方式首选?

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:0)

对于您的示例,我可能会选择选项1,因为它更简单,更容易阅读,并且您没有加载那么多对象,因此我认为性能损失不会太严重。

如果您可能正在加载更多数据(例如,如果您取消了limit(20)部分),我会使用选项2,因为它可以帮助您在实例化所有需要的时候实例化Category对象他们的名字。在较小的列表中,这种开销可能可以忽略不计,但随着列表变长,它可能变得很重要。

答案 2 :(得分:0)

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

尽管如此,我并没有看到使用includes是一件大事。特别是在开发应用程序时,您在页面上的内容将会发生变化。

在我看来,在这种情况下,大部分时间都只使用includes。除非您在行中存储了大量text,否则您的生产和查询最终成为瓶颈,那么您应该花时间并优化它。