在Ruby on Rails中加速find_by搜索

时间:2011-10-04 12:29:58

标签: ruby-on-rails ruby performance ruby-on-rails-3 sql-server-2008

我有一个名为Staging的表格,我将excel电子表格中的所有数据放入其中,通过查找现有模型/表格从中获取ID号,然后将其与当前数据库进行比较这是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 个答案:

答案 0 :(得分:1)

加快尝试

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没有用零初始化所有值吗?

答案 1 :(得分:0)

如果你只有几百行,那么你可以尝试分三步:

  1. 旋转电子表格以收集所有应用,服务器和环境名称/代码。
  2. 将您的应用,服务器和环境批量加载到哈希值中。
  3. 再次旋转电子表格以进行Staging.create来电。
  4. 这样的事情:

    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...,而不是仅仅做一次。