优化代码以填充巨大表中的新列

时间:2013-05-25 09:58:21

标签: mysql ruby-on-rails ruby

我要将一个新列添加到一个包含37M行的表中。该列将包含一个关联ID。

简单模型:

class SeenEpisode < ActiveRecord::Base
  #show_id is the new column
  attr_accessible :user_id, :season_id, :episode_id, :show_id
  belongs_to :episode
  belongs_to :season
end

这是我能想到的最快方式:

seen_episodes = SeenEpisode.where("show_id IS NULL")
seen_episodes.find_in_batches do |batch| #batch size is 1000
  batch.group_by(&:season_id).each do |season_id, seen_episodes|
    #all seen_episodes with the same season_id, ensures the same show_id
    show_id = seen_episodes.first.episode.show_id
    seen_episodes.each do |seen_episode|
      seen_episode.update_column(:show_id, show_id) #skip validations and callbacks
    end
  end
end

目前的开发测试表明,填充10.000条记录大约需要2分钟 让我们说生产需要1分钟,由于更好的硬件和mysql配置,它仍然需要每百万条记录100分钟。那就像60个小时。

有没有机会更快地解决这个问题?

1 个答案:

答案 0 :(得分:3)

如果您批量写入,它将更快的数量级。我的意思是,而不是发送个人写

update episodes set show_id = 1 where episode_id = 1;
update episodes set show_id = 1 where episode_id = 2;
update episodes set show_id = 1 where episode_id = 3;

您应该将它们分组到一个写

update episodes set show_id = 1 where episode_id in (1, 2, 3);

或者,这样的事情可以起作用:

select season_id, show_id 
from episodes 
where show_id is not null 
group by season_id;

应该为每个show_id获取一个season_id。然后只需循环遍历那些行并激活大量更新(为简单起见,SQL语法,你可能会在ruby中执行此操作)

update episodes set show_id = @show_id where season_id = @season_id;