【问题标题】:Best practices for getting a list of IDs from an ActiveRecord model从 ActiveRecord 模型中获取 ID 列表的最佳实践
【发布时间】:2009-06-19 15:01:25
【问题描述】:

我有一个 ActiveRecord 模型 Language,带有 idshort_code 列(还有其他列,但它们与这个问题无关)。我想创建一个方法,该方法将获得一个短代码列表,并返回一个 ID 列表。我不关心关联,我只需要最终得到一个看起来像 [1, 2, 3, ...] 的数组。

我的第一个想法是做类似的事情

def get_ids_from_short_codes(*short_codes)
  Language.find_all_by_short_code(short_codes.flatten, :select => 'id').map(&:id)
end

但我不确定这是否不必要地浪费时间/内存/处理。

我的问题有两个:

  1. 有没有办法运行 ActiveRecord 查找,它只返回某个表列的数组而不是实例化对象?
  2. 如果是这样,收集长度为 n 的数组而不是实例化 n ActiveRecord 对象真的值得吗?

请注意,对于我的特定目的,n 大约是 200。

【问题讨论】:

    标签: ruby-on-rails optimization activerecord


    【解决方案1】:

    在 Rails 3.x 中,您可以使用 pluck 方法从请求的字段中返回值,而无需实例化对象来保存它们。

    这会给你一个 ID 数组:

    Language.where(short_code: short_codes.flatten).pluck(:id)
    

    我应该提到的是,在 Rails 3.x 中,您一次只能提取一列,但在 Rails 4 中,您可以传递多列来提取。

    顺便说一下,这是similar answersimilar question

    【讨论】:

    • 在大多数情况下,您可以使用 .ids 代替 .pluck(:id) 作为速记。
    【解决方案2】:

    老实说,对于 200 条记录,我不会担心。当您达到 2000、20,000 或 200,000 条记录时,您就可以担心优化了。

    确保您的表中有 short_code 索引。

    如果您仍然担心性能,请查看 development.log 并查看该特定调用的数据库编号。您可以调整查询并查看它如何影响日志中的性能。这应该可以让您粗略估计性能。

    【讨论】:

    • 谢谢,这是有道理的。我想我只是担心当我只想要一列时实例化对象会过大。
    【解决方案3】:

    同意前面的回答,但如果一定要,可以试试这个

    sql = Language.send(:construct_finder_sql, :select => 'id', :conditions => ["short_code in (?)", short_codes])
    Language.connection.select_values(sql)
    

    虽然有点难看,但它不会创建内存对象。

    【讨论】:

    • 这很好用,如果你有数千条记录,它比对象路由快很多。唯一的缺点是,如果您在包含的依赖项上有 WHERE 条件(construct_finder_sql 不包括连接),它就不起作用
    【解决方案4】:

    如果您使用关联,则可以直接从 ActiveRecord 获取原始 ID。 例如:

    class User < ActiveRecord::Base
      has_many :users
    end
    
    irb:=> User.find(:first).user_ids
    irb:>> [1,2,3,4,5]
    

    【讨论】:

    • 这是执行此操作的最佳选择。谢谢。
    【解决方案5】:

    Phil 对此是正确的,但如果您确实发现这是一个问题。您可以将原始 SQL 查询发送到数据库并在 ActiveRecord 以下的级别上工作。这对于这种情况很有用。

    ActiveRecord::Base.connection.execute("SQL CODE!")
    

    在使用此功能之前先对代码进行基准测试。

    【讨论】:

      【解决方案6】:

      这真的是一个选择问题。

      不管是否矫枉过正,ActiveRecord 应该为您提供对象,因为它是一个 ORM。就像 Ben 说的那样,如果您不想要对象,请使用原始 SQL。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-05
        • 1970-01-01
        • 1970-01-01
        • 2016-08-26
        • 1970-01-01
        • 1970-01-01
        • 2011-01-19
        相关资源
        最近更新 更多