Ускорьте поиск find_by в Ruby on Rails - PullRequest
0 голосов
/ 04 октября 2011

У меня есть таблица с именем Staging, в которую я помещаю все данные из электронной таблицы Excel, получаю из нее идентификационный номер, просматривая существующую модель / таблицу, а затем сравниваю ее с текущей базой данных, которая SQL Server 2008.

Мой код выглядит следующим образом:

def compare 

require 'rubygems'
require 'spreadsheet'
require 'set'

Spreadsheet.client_encoding = 'UTF-8'
file_full_path = File.expand_path(File.join(File.dirname(__FILE__), "../../SISlist.xls"))
book = Spreadsheet.open(file_full_path) #Select excel file
sheet = book.worksheet 0 #Select 1st worksheet
app,server,env = 0

for i in 1..500
  row = sheet.row(i)

    if row[0].to_s != "" # Makes sure no empty cells are saved
     row.each do |t|
     app = App.find_by_name(row[0].to_s)
     server = Server.find_by_name(row[2].to_s)
     env = Environment.find_by_code(row[3].to_s)
    end
Staging.create(:app => app.id, :server => server.id, :environment => env.id)
  end
 end
end

Проблема, с которой я столкнулся сейчас, заключается в том, что этот метод занимает очень много времени (почти 20 секунд), тогда как все другие мои методы подобного рода не занимают так много времени.

Любой способ ускорить этот процесс или, возможно, мой рабочий процесс неверен, и, следовательно, вся архитектура неверна?

Требуется помощь

Ответы [ 2 ]

1 голос
/ 04 октября 2011

Чтобы ускорить, попробуйте

ActiveRecord::Base.transaction do
  500.times do |i|
    row = sheet.row(i)
    if row[0].to_s != "" # Makes sure no empty cells are saved
      app = App.find_by_name(row[0].to_s)
      server = Server.find_by_name(row[2].to_s)
      env = Environment.find_by_code(row[3].to_s)
      Staging.create(:app => app.id, :server => server.id, :environment => env.id)
     end
  end
end

и знаете ли вы, что app,server,env = 0 не инициализирует все значения с нуля?

0 голосов
/ 04 октября 2011

Если у вас всего пара сотен строк, вы можете попробовать сделать это в три этапа:

  1. Прокрутить электронную таблицу, чтобы собрать все имена / коды приложений, серверов и сред.
  2. Массовая загрузка вашего приложения, сервера и среды в хэши.
  3. Повторная прокрутка электронной таблицы для повторных вызовов Staging.create.

Примерно так:

sets = {
    :apps         => Set.new,
    :servers      => Set.new,
    :environments => Set.new
}
(1 .. 500).select { |i| !sheet.row(i).to_s.empty? }.each do |i|
    sets[:apps].add(row[0].to_s)
    #...
end

# You could just pull in the ids and names here rather than whole objects too.
sets[:apps] = Set.where(:name => sets[:apps].to_a).each_with_object({ }) { |a,h| h[a.name] = a.id }
#...

(1 .. 500).select { |i| !sheet.row(i).to_s.empty? }.each do |i|
    Staging.create(
        :app => sets[:apps][row[0].to_s],
        #...
    )
end

По сути, я предполагаю, что ваш самый большой хит - это звонить find_by... снова и снова, а не делать это один раз.

...