эффективная база данных направляющих массового обновления

Я пытаюсь создать утилиту граблей, которая обновит мою базу данных время от времени.

Это - код, который я имею до сих пор:

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

Проблема, которую я имею, состоит в том, что это занимает несколько минут для ввода 100 тысяч плюс записи. Я хотел бы найти более эффективный способ обновить мою базу данных. Идеально это останется независимым от типа БД, но если не мой рабочий сервер будет работать на MySQL.

Спасибо за любое понимание.

5
задан skaffman 16 March 2012 в 15:22
поделиться

4 ответа

Вы пробовали использовать AR Extensions для массового импорта? Вы получаете впечатляющие улучшения производительности, когда вставляете в БД тысячи строк. Посетите их веб-сайт для получения более подробной информации.

См. Эти примеры для получения дополнительной информации

Пример использования 1

Пример использования 2

Пример использования 3

9
ответ дан 18 December 2019 в 13:13
поделиться

Как говорит Ларри, используйте специальные утилиты импорта для БД, если файл имеет нужный вам формат. Однако, если вам нужно манипулировать данными перед вставкой, вы можете сгенерировать один запрос INSERT с данными для многих строк, что быстрее, чем использование отдельного запроса для каждой строки (как это делает ActiveRecord). Например:

INSERT INTO iptocs (ip_from, ip_to, country_code) VALUES
  ('xxx', 'xxx', 'xxx'),
  ('yyy', 'yyy', 'yyy'),
  ...;
0
ответ дан 18 December 2019 в 13:13
поделиться

Используйте утилиты уровня базы данных для высокой скорости работы Luke!

К сожалению, они специфичны для db. Но они быстрые. Для mysql смотрите http://dev.mysql.com/doc/refman/5.1/en/load-data.html

3
ответ дан 18 December 2019 в 13:13
поделиться

Джимми Богард (автор Automapper) написал отличную статью о том, как он структурирует свой код, что может помочь в принятии решения.

Я работал над проектами с тоннами отдельных сборок и проектов, которые имеют небольшое количество. Мое личное предпочтение состоит в том, чтобы иметь меньше собраний, так как мне всегда легче работать. Если вы используете хорошие принципы кодирования (например, ТЕЛО), то это не имеет значения, если вы используете 2 или 20 сборок.

-121--4746256-

Используйте серию Тейлора и попробуйте найти связь между членами серии, чтобы не вычислять вещи снова и снова

Вот пример для косинуса:

double cosinus(double x, double prec)
{
    double t, s ;
    int p;
    p = 0;
    s = 1.0;
    t = 1.0;
    while(fabs(t/s) > prec)
    {
        p++;
        t = (-t * x * x) / ((2 * p - 1) * (2 * p));
        s += t;
    }
    return s;
}

с помощью этого мы можем получить новый член суммы с помощью уже используемого (мы избегаем факториала и x 2p )

explanation

-121--590606-

Вы можете создать текстовый файл со всеми необходимыми INSERT, а затем выполнить:

mysql -u user -p db_name < mytextfile.txt

Не уверен, будет ли это быстрее, но стоит попробовать...

1
ответ дан 18 December 2019 в 13:13
поделиться
Другие вопросы по тегам:

Похожие вопросы: