这是我的导入脚本。我有大约40万条记录。我的连接在插入记录时关闭。如何将其拆分成较小的碎片?
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
答案 0 :(得分: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
这样做,我怀疑你会看到超时错误。
答案 1 :(得分:0)
如果连接在插入记录时关闭,为什么不让脚本将SQL语句写入文件,然后对数据库运行这些插入?
所以:
这样看似可以防止OOM错误。
答案 2 :(得分:0)
前段时间我有同样的问题。我找到的最佳解决方案是使用resque的后台作业。请参阅this回答。
我还使用resque-status向用户显示WIP。