Ruby on rails 高效的rails数据库批量更新

Ruby on rails 高效的rails数据库批量更新,ruby-on-rails,activerecord,bulkinsert,Ruby On Rails,Activerecord,Bulkinsert,我正在尝试构建一个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 databas

我正在尝试构建一个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
namespace:utils-do
#utils:update\u ip
#将文件frim下载到临时文件夹,然后在中解压
#然后更新数据库。
描述“将ip更新到国家/地区数据库”
任务:更新_ip=>:环境do
需要“打开uri”
需要“拉链/拉链系统”
需要“csv”
文件\u name=“ip to country.csv”
file_path=“#{RAILS_ROOT}/db/”+文件名
url='1〕http://ip-to-country.webhosting.info/downloads/ip-to-country.csv.zip'
#上次更新数据库时检查。
mod_时间=“”
mod_time=File.new(File_path).mtime.httpdate如果File.exe存在?文件路径
开始
放置“下载更新…”
#将条件GET发送到服务器
zipped_file=open(url,{'If-Modified-Since'=>mod_time})
rescue OpenURI::HTTPError=>_错误
如果_error.io.status[0]=“304”
将“无需更新”
其他的
将“HTTPError:”与_error.message一起放入
结束
else#文件下载时未出错。
Rails.logger.info“ip到coutry:上次更新远程数据库:'+zip_file.meta['last-modified']
延迟=Time.now-压缩的\u文件.last\u修改
Rails.logger.info“国家/地区的ip:数据库已过期:{delay}秒({delay/60/60/24}天)”
放“解压…”
如果File.exe存在,是否删除(文件路径)?文件路径
Zip::ZipFile.open(zipped_file.path)do | ZipFile|
解压缩(文件名、文件路径)
结束
Iptocs.delete_all
放入“导入新数据库…”
#TODO:太重了,找一个更好的解决方案。
CSV.open(文件路径,'r')do |行|
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
结束#CSV
把“完成”
结束#开始恢复
结束#任务
结束#名称空间
我遇到的问题是,输入10多万个条目需要几分钟的时间。我想找到一种更有效的方法来更新我的数据库。理想情况下,这将保持独立于数据库类型,但如果不是,我的生产服务器将在MySQL上运行


感谢您的帮助。

您可以生成一个包含所有所需插入内容的文本文件,然后执行:

mysql -u user -p db_name < mytextfile.txt
mysql-u user-p db_name

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

使用数据库级实用程序进行高速运行

不幸的是,它们是db特有的。但它们很快
对于mysql,请参见Larry所说的,如果文件的格式符合您的需要,请使用特定于DB的导入实用程序。但是,如果需要在插入之前操作数据,可以为多行生成包含数据的单个插入查询,这比为每行使用单独的查询要快(就像ActiveRecord所做的那样)。例如:

INSERT INTO iptocs (ip_from, ip_to, country_code) VALUES
  ('xxx', 'xxx', 'xxx'),
  ('yyy', 'yyy', 'yyy'),
  ...;
您是否尝试过使用散装进口?当您向DB插入1000行时,您将获得令人印象深刻的性能改进。有关更多详细信息,请访问他们的网站

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


我目前正在试验activerecord导入,这听起来很有希望:


Rails本身使用SQL insert语句。-查看rails日志。因此,这种方法不会提高速度。当然,Rails会插入,否则它将如何向数据库添加记录?但在他最初的文章中,作者使用的是“save”方法,它比简单的插入有更多的开销。我确信它涉及到在每次插入时进行提交,进行模型验证,等等。gem支持从CSV导入。这消除了
ActiveRecord
实例化和验证成本。有关更多详细信息,请参阅本文。用于Rails 3的现在是activerecord导入: