0

这是我的导入脚本。我有大约 400 000 条记录。并且在插入记录期间我的连接关闭。如何将其拆分为更小的部分?

  def extract_to_database(collection)
    tmp       = []
    type      = K
    inserts = []

    collection.each_with_index do |line, i|
      _type    = line.strip
      _changed = TYPES.include? _type

      if _changed && i > 0
        case type
        when K then @k << tmp
        when F then @f << tmp
        when FB then @f << tmp
        when I, D
          pharmaceutic = Pharmaceutic.find_by pzn: tmp[PZN]
          if pharmaceutic
            inserts.push "(#{pharmaceutic.id}, '#{tmp[UNIT]}', '#{tmp[DOSE]}')"
          end
        end

        tmp  = []
        type = _type
      end

      tmp << clean(line)
    end
    sql = "INSERT INTO pharmaceutic_dosages (`pharmaceutic_id`, `unit`, `dose`) VALUES #{inserts.join(", ")}"
    CONN.execute sql
  end
4

3 回答 3

1

您的问题缺少很多需要的信息,特别是您正在使用的 DBM、您的超时值设置为什么、您在代码中打开数据库连接的位置、您的代码实际需要多长时间来处理400,000 条记录等等。所有这些都会影响你工作的成败。

这段代码引起了我的注意:

sql = "INSERT INTO pharmaceutic_dosages (`pharmaceutic_id`, `unit`, `dose`) VALUES #{inserts.join(", ")}"
CONN.execute sql

您在哪里打开与数据库的连接?为什么你打开它然后不立即使用它?数据库配置为在一段时间后关闭未使用的连接,因为连接会占用内存和 CPU 时间。连接后,发送更新/删除/插入,无论如何,然后关闭它。如果您不断地连接/关闭,您只需要一个持久的连接,这也可能是 DBM/服务器的大量 CPU 消耗。

不要在计算时打开然后保持连接,而是等到数据准备好后再打开它,然后打开它并立即发送。我不知道您使用的是什么驱动程序或 DBM,因此请考虑以下伪代码:

sql = "INSERT INTO pharmaceutic_dosages (`pharmaceutic_id`, `unit`, `dose`) VALUES #{inserts.join(", ")}"    
CONN = connect_to_database(...)
CONN.execute sql
CONN.close

这样做,我怀疑你会看到超时错误。

于 2013-10-28T23:37:46.913 回答
0

前段时间我有同样的问题。我找到的最佳解决方案是使用 resque 的后台作业。看到这个答案。

我还使用resque-status向用户显示 WIP。

于 2013-10-28T16:39:27.990 回答
0

如果连接在插入记录时关闭,为什么不让脚本将 SQL 语句写入文件,然后对数据库运行这些插入?

所以:

  1. 按照上面的脚本生成 SQL 语句。
  2. 将它们写入文件(本地或 S3 上)。
  3. 复制该文件的内容并在数据库控制台中运行。

似乎这也可以防止OOM错误。

于 2013-10-28T16:34:07.183 回答