如何在rails应用程序中将大型csv文件导入mysql?

如何在rails应用程序中将大型csv文件导入mysql?,mysql,ruby-on-rails,csv,heroku,Mysql,Ruby On Rails,Csv,Heroku,我正在rails应用程序中实现将csv数据导入mysql。我使用CSV.parse逐行读取CSV文件并导入数据库。这种方法很有效 但是,当我部署到Heroku服务器时,每个请求的超时时间是30秒。如果导入csv文件超过30秒。Heroku服务器出现错误:请求超时-H12。有人帮我找到导入大型csv文件的最佳方法吗?现在,我只导入包含70个用户的小型csv。我想导入大型csv包括500-1000个用户。代码如下: 导入控制器: CSV.foreach(params[:file].path, :h

我正在rails应用程序中实现将csv数据导入mysql。我使用CSV.parse逐行读取CSV文件并导入数据库。这种方法很有效


但是,当我部署到Heroku服务器时,每个请求的超时时间是30秒。如果导入csv文件超过30秒。Heroku服务器出现错误:请求超时-H12。有人帮我找到导入大型csv文件的最佳方法吗?现在,我只导入包含70个用户的小型csv。我想导入大型csv包括500-1000个用户。代码如下:

导入控制器:

CSV.foreach(params[:file].path, :headers => true) do |row|
  i = i + 1

  if i == 1
    @company = Company.find_or_create_by!(name: row[0])       
  end

  @users = User.find_by(email: row[1])

  if @users
    if @company.id == @users.employee.company_id
      render :status=> 401, :json => {:message=> "Error"}
      return
    else
      render :status=> 401, :json => {:message=> "Error"}
      return
    end
  else
    # User
    # # Generate password
    password = row[2]
    user = User.new(email: row[1])
    user.password = password.downcase
    user.normal_password = password.downcase
    user.skip_confirmation!
    user.save!

    obj = {
      'small'   => 'https://' + ENV['AWS_S3_BUCKET'] + '.s3.amazonaws.com/images/' + 'default-profile-pic_30x30.png',
      'medium'  => 'https://' + ENV['AWS_S3_BUCKET'] + '.s3.amazonaws.com/images/' + 'default-profile-pic_40x40.png'
    }

    employee = Employee.new(user_id: user.id)
    employee.update_attributes(name: row[3], job_title: row[5], gender: row[9], job_location: row[10], group_name: row[11], is_admin: to_bool(row[13]), 
                is_manager: to_bool(row[14]), is_reviewee: to_bool(row[6]), admin_target: row[7], admin_view_target: row[12], department: row[8], 
                company_id: @company.id, avatar: obj.to_json)
    employee.save!

  end
end

我曾尝试使用gems“activerecord import”或“fastercsv”,但“activerecord import”不起作用,“fastercsv”不适用于ruby 2.0和rails 4.0

if i == 1
  @company = Company.find_or_create_by!(name: row[0])       
end

@users = User.find_by(email: row[1])
在30秒的时间范围内需要大量的计算周期

我建议您使用resquedelayed_job将例程转换为Heroku后台进程,或者将例程拆分为n请求,如果我们无法对上述代码进行优化的话


希望这有帮助。

在控制器中执行此操作对我来说似乎有点过分,尤其是因为它阻塞了。你有没有想过把它投入到背景工作中去

如果我是你,我会:

  • 上传文件
  • 在后台将其作为rake任务进行解析

  • 另外,请查看:

    在后台处理您的CSV,使用诸如
    延迟作业
    sidekiq
    重新创建
    等产品。如果它适合您的使用情况,您甚至可以使用
    guard
    cron

    执行此操作。我仍然尝试使用rake任务命令,但客户端希望从UI导入:-s。抱歉,客户端希望从UI控制器导入用户,他们不知道后台作业。谢谢,我将尝试。我不能优化上面的代码。项目中的逻辑非常复杂。但是,您可以为我解释“将您的例程转换为Heroku后台进程,或将例程拆分为n个请求”。很抱歉,不清楚,我在说Heroku后台进程时提到了诸如resque和delayed_job之类的gems。至于“将例程拆分为n个请求”,我的意思是只读取并保存一个(或30秒内的任何数量)控制器中的用户,而不是一次解析所有用户。但是从您的附加信息来看,将其作为后台进程处理似乎更容易实现。谢谢。因为我的客户希望从UI控制器导入用户。我只是想,调用后台作业(rake任务命令)在控制器内部???您可以从控制器调用后台作业,但实现并不限于rake任务。使用上述gems实现BG作业的优点之一是,您甚至可以监视/恢复暂停作业。有关我可以从导入控制器运行rake任务后台作业的想法,请参见此处,对吗?
    rake::任务['Task\u name'].调用(args)
    。但我不建议这样做。rake任务应该从控制器外部调用-
    cron
    guard
    。当然,您可以执行
    系统(“rake…”)
    或反勾号或
    %x[]