Я пытаюсь создать утилиту граблей, которая обновит мою базу данных время от времени.
Это - код, который я имею до сих пор:
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.
Спасибо за любое понимание.
Вы пробовали использовать AR Extensions для массового импорта? Вы получаете впечатляющие улучшения производительности, когда вставляете в БД тысячи строк. Посетите их веб-сайт для получения более подробной информации.
См. Эти примеры для получения дополнительной информации
Как говорит Ларри, используйте специальные утилиты импорта для БД, если файл имеет нужный вам формат. Однако, если вам нужно манипулировать данными перед вставкой, вы можете сгенерировать один запрос INSERT с данными для многих строк, что быстрее, чем использование отдельного запроса для каждой строки (как это делает ActiveRecord). Например:
INSERT INTO iptocs (ip_from, ip_to, country_code) VALUES
('xxx', 'xxx', 'xxx'),
('yyy', 'yyy', 'yyy'),
...;
Используйте утилиты уровня базы данных для высокой скорости работы Luke!
К сожалению, они специфичны для db. Но они быстрые. Для mysql смотрите http://dev.mysql.com/doc/refman/5.1/en/load-data.html
Джимми Богард (автор 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 )
-121--590606-Вы можете создать текстовый файл со всеми необходимыми INSERT, а затем выполнить:
mysql -u user -p db_name < mytextfile.txt
Не уверен, будет ли это быстрее, но стоит попробовать...