【问题标题】:ActiveRecord#create does not allow to set the idActiveRecord#create 不允许设置 id
【发布时间】:2014-11-13 15:41:53
【问题描述】:

我需要批量插入 > 100.000 条记录。 id 不会由数据库创建,我必须使用给定的 UUID: 使用 mymodel.new 分配 ID 在循环中执行此操作,然后保存记录将起作用,但速度太慢(大约 20 分钟)

当我创建一个数组“记录”并使用 mymodel.create(records) 时,我遇到了“无法批量分配 id”问题。 我已经尝试了所有我能找到的解决方案:

  • 'attr_accessible :id, ...' 用于模型。适用于除 id 之外的所有人。
  • (重新)定义'def self.attributes_protected_by_default [] end' - 无效
  • 一个建议是使用 'create' 和 ':without_protection => true',但 create 不接受多个参数。

.所以这些解决方案都没有帮助。 我还能做什么?

【问题讨论】:

  • 记录中的id存放在id列重要吗?也许创建一个 external_id 列并在其中插入 id 并避免在 mass_assignment 上与 rails 争吵?

标签: activerecord mass-assignment


【解决方案1】:

最后,我找到了一个解决方案,它在 Rails 方式中可能并不优雅,但它解决了我的性能问题:

起初我尝试了@Albin 的建议,结果发现 create(records) 并没有更快地工作(仍然 > 15 分钟)。

我现在的解决办法是:

  • 创建一个临时 CSV 文件

    db_tmp = File.open("tmp_file", "w")
    records = ""
    @data_records.each do |row|
      records << "#{row['id']},#{row['id']},#{field_1},#{row['field_2']}, ... \n"
    end
    db_tmp.write(records)
    db_tmp.close
    
  • 使用加载数据命令执行 sql

    sql = "load data infile 'tmp_file' into table my_table 
      fields optionally enclosed by '\"' terminated by ','
      (id,field_1,field_2, ... )"
    ActiveRecord::Base.connection.execute(sql)
    

整个过程现在持续不到 1 (!) 分钟,包括通过网络获取数据并将原始 json 消息解析为哈希。

我知道这并没有说明如何欺骗 create 以允许 ID 分配,但性能问题已解决。

另一点是我的解决方案绕过了为模型定义的任何验证。这不是问题,因为在这种情况下,我知道我可以依赖接收到的数据的完整性 - 如果出现问题,加载将失败并且执行会引发异常。

【讨论】:

    猜你喜欢
    • 2021-12-29
    • 2014-05-23
    • 2012-04-05
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多