【问题标题】:efficient bulk update rails database高效的批量更新 Rails 数据库
【发布时间】:2011-01-18 02:28:34
【问题描述】:

我正在尝试构建一个 rake 实用程序,它会不时更新我的​​数据库。

这是我目前的代码:

namespace :utils do

  # utils:update_ip
  # Downloads the file frim <url> to the temp folder then unzips it in <file_path>
  # Then updates the database.

  desc "Update ip-to-country database"
  task :update_ip => :environment do

    require 'open-uri'
    require 'zip/zipfilesystem'
    require 'csv'

    file_name = "ip-to-country.csv"
    file_path = "#{RAILS_ROOT}/db/" + file_name
    url = 'http://ip-to-country.webhosting.info/downloads/ip-to-country.csv.zip'


    #check last time we updated the database.
    mod_time = ''
    mod_time = File.new(file_path).mtime.httpdate    if File.exists? file_path

    begin
      puts 'Downloading update...'
      #send conditional GET to server
      zipped_file = open(url, {'If-Modified-Since' => mod_time})
    rescue OpenURI::HTTPError => the_error
      if the_error.io.status[0] == '304'
        puts 'Nothing to update.'
      else
        puts 'HTTPError: ' + the_error.message
      end
    else # file was downloaded without error.

      Rails.logger.info 'ip-to-coutry: Remote database was last updated: ' + zipped_file.meta['last-modified']
      delay = Time.now - zipped_file.last_modified
      Rails.logger.info "ip-to-country: Database was outdated for: #{delay} seconds (#{delay / 60 / 60 / 24 } days)"

      puts 'Unzipping...'
      File.delete(file_path) if File.exists? file_path
      Zip::ZipFile.open(zipped_file.path) do |zipfile|
        zipfile.extract(file_name, file_path)
      end

      Iptocs.delete_all

      puts "Importing new database..."


      # TODO: way, way too heavy find a better solution.


      CSV.open(file_path, 'r') do |row|
        ip = Iptocs.new(  :ip_from        => row.shift,
                        :ip_to          => row.shift,
                        :country_code2  => row.shift,
                        :country_code3  => row.shift,
                        :country_name   => row.shift)
        ip.save
      end #CSV
      puts "Complete."

    end #begin-resuce
  end #task
end #namespace

我遇到的问题是输入 10 万多个条目需要几分钟时间。我想找到一种更有效的方式来更新我的数据库。理想情况下,这将保持独立于数据库类型,但如果不是,我的生产服务器将在 MySQL 上运行。

感谢您提供任何见解。

【问题讨论】:

    标签: ruby-on-rails activerecord bulkinsert


    【解决方案1】:

    您可以生成一个包含您需要的所有 INSERT 的文本文件,然后执行:

    mysql -u user -p db_name < mytextfile.txt
    

    不确定这是否会更快,但值得一试...

    【讨论】:

    • Rails 本身使用 SQL 插入语句。 -- 查看您的 Rails 日志。所以这种方法不会提高速度。
    • Rails 当然会进行 INSERTS,否则它会如何将记录添加到数据库中?但是在他的原始帖子中,作者使用了“保存”方法,这比简单的插入具有更多的开销。我确信它涉及对每个插入进行提交、进行模型验证等
    【解决方案2】:

    使用数据库级实用程序实现高速 Luke!

    不幸的是,它们是特定于数据库的。但他们很快 对于mysql,见http://dev.mysql.com/doc/refman/5.1/en/load-data.html

    【讨论】:

      【解决方案3】:

      正如 Larry 所说,如果文件以您想要的格式出现,请使用特定于 DB 的导入实用程序。但是,如果您需要在插入之前操作数据,您可以生成一个包含多行数据的单个 INSERT 查询,这比对每一行使用单独的查询要快(就像 ActiveRecord 会做的那样)。例如:

      INSERT INTO iptocs (ip_from, ip_to, country_code) VALUES
        ('xxx', 'xxx', 'xxx'),
        ('yyy', 'yyy', 'yyy'),
        ...;
      

      【讨论】:

        【解决方案4】:

        您是否尝试过使用AR Extensions 进行批量导入?当您将 1000 行插入 DB 时,您将获得令人印象深刻的性能改进。访问他们的website了解更多详情。

        有关更多信息,请参阅这些示例

        Usage Example 1

        Usage Example 2

        Usage Example 3

        【讨论】:

        【解决方案5】:

        我目前正在尝试使用 activerecord-import,这听起来很有希望:

        https://github.com/zdennis/activerecord-import

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-01-24
          • 2014-10-14
          • 1970-01-01
          • 1970-01-01
          • 2021-10-11
          • 2016-02-13
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多