我会尝试扩展我的问题标题。我从事ruby项目。我必须处理存储在CSV文件中的大量数据(大约120000)。我必须阅读这些数据,处理并放入DB。现在需要几天时间。我必须加快速度。问题是,有时在处理过程中我会遇到一些异常,我必须重复整个导入过程。我认为更重要的是提高性能,而不是使用少量数据查找错误。现在我坚持使用CSV文件。我决定对处理脚本进行基准测试以找到瓶颈并改进从CSV加载数据。我看到以下步骤:
现在我使用标准的ruby CSV库。你推荐一些更好的宝石吗?
如果你们中的一些人对类似问题很熟悉,那么很高兴认识你们。
编辑:
数据库:postgrees
系统:linux
答案 0 :(得分:3)
我没有机会亲自测试,但我明确地通过这篇文章,似乎做了这个工作。
您必须适应使用CSV而不是XLSX。 如果该站点将在此处停止代码,以供将来参考。 它的工作原理是在数据库中同时写入BATCH_IMPORT_SIZE记录,应该给予巨大的利润。
class ExcelDataParser
def initialize(file_path)
@file_path = file_path
@records = []
@counter = 1
end
BATCH_IMPORT_SIZE = 1000
def call
rows.each do |row|
increment_counter
records << build_new_record(row)
import_records if reached_batch_import_size? || reached_end_of_file?
end
end
private
attr_reader :file_path, :records
attr_accessor :counter
def book
@book ||= Creek::Book.new(file_path)
end
# in this example, we assume that the
# content is in the first Excel sheet
def rows
@rows ||= book.sheets.first.rows
end
def increment_counter
self.counter += 1
end
def row_count
@row_count ||= rows.count
end
def build_new_record(row)
# only build a new record without saving it
RecordModel.new(...)
end
def import_records
# save multiple records using activerecord-import gem
RecordModel.import(records)
# clear records array
records.clear
end
def reached_batch_import_size?
(counter % BATCH_IMPORT_SIZE).zero?
end
def reached_end_of_file?
counter == row_count
end
end
答案 1 :(得分:1)
有几种方法可以解决这个问题。我个人会推荐SmarterCSV,这使得使用阵列哈希处理CSV更快更容易。如果可能的话,你肯定应该分开工作,或者使用Redis
制作要处理的文件队列并分批处理答案 2 :(得分:1)
确保您的Ruby脚本可以处理作为参数给出的多个文件,即您可以像这样运行它:
script.rb abc.csv def.csv xyz.csv
然后使用这样的GNU Parallel
并行化它以保持所有CPU内核忙碌:
find . -name \*.csv -print0 | parallel -0 -X script.rb
-X
将尽可能多的CSV文件传递给Ruby作业,而不会超出命令行的最大长度。如果您希望-j 8
一次运行8个作业,则可以在parallel
之后添加GNU Parallel
,并且可以使用--eta
来获取预计到达/结束时间:
find . -name \*.csv -print0 | parallel -0 -X -j 8 --eta script.rb
默认情况下,GNU Parallel
将与CPU内核并行运行多个作业。