我们开发的时候遇到一种情况,业务量小的时候设计了一张表来存帖子:
posts(id, topic_id, content, status, created_at, updated_at)
当数据量达到百万的量级后,发现此表查找非常慢,这时候想从数据库的角度来改进。
比较常用的方法是,把posts表中的大块数据的字段拆分出来,作为一个子表:
posts(id, topic_id, status, created_at, updated_at)
post_contents(post_id, content)
为了保证其他层不做修改,我们用代理的办法。
class Post < ActiveRcord::Base
has_one :post_content, :class_name=>'PostContent',:foreign_key=>'post_id'
def content
post_content ? post_content.content : nil
end
def content=(txt)
if post_content
post_content.content = txt
else
build_post_content(:content=>txt) unless txt.blank?
end
end
end
针对这个应用,我们自己搞了个通用方法加入ActiveRecord::Base
def self.forward_with_create(obj_name,attr_names)
attr_names.each do |attr_name|
define_method(attr_name) do |*args|
obj = send(obj_name)
obj ? obj.send(attr_name) : nil
end
define_method("#{attr_name}=") do |*args|
obj = send(obj_name)
val = args[0]
if obj
if obj.send(attr_name) != val
obj.send("#{attr_name}=",val)
end
else
send("build_#{obj_name}",{attr_name=>val}) if !val.blank?
end
end
end
end
这样,我们的Post就变成:
class Post < ActiveRcord::Base
has_one :post_content, :class_name=>'PostContent',:foreign_key=>'post_id'
forward_with_create(:post_content,[:content])
end