Gem redundant_column

hooopo · 2012年07月13日 · 最后由 hooopo 回复于 2012年07月17日 · 3211 次阅读

冗余列优化是数据库优化的常见方法。一些情况,由于一个字段在其他表里,在查询的时候就需要做 JOIN 查询。比如:查询积分大于 100 的用户的帖子,状态是 active 的用户的文章等。

优化这样的查询的办法之一就是使用冗余列,上面的例子把用户积分冗余到帖子表里,把用户状态冗余到文章表里。这样只需要简单的查询就可以了。

但是冗余列会带来数据的不一致性。这就需要额外的维护成本。比如,用户状态的变化要同步到文章表。 还有就是每次创建文章都需要手动设置用户状态。

redundant_column 就是解决上面问题的插件。

简单的使用方法:

class User < ActiveRecord::Base has_many :topics, :redundant_column => {:status => :user_status} end

class Topic < ActiveRecord::Base belongs_to :user, :redundant_column => {:user_status => :status} end

user = User.create(:name => "Hooopo", :status => "active")

topic = Topic.create(:user => user, :title => "this is title")

assert_equal topic.user_status, user.status

user.status = "disable" user.save

topic.reload

assert_equal topic.user_status, user.status

我觉得就那些查询的时候需要 aggregate 的才要冗余吧...

#1 楼 @bhuztez aggregate 是指? 我觉得普通的 has many 关联就可以啊。

#2 楼 @hooopo 我是说用户积分还不如直接 JOIN,冗余估计也不能改善多少啊

#3 楼 @bhuztez 这得看实际表的大小还有查询的频繁程度。上面的只是例子。 冗余以后还可以根据查询做符合索引等进一步优化。

@hooopo 说到冗余,求教一个问题,比如说各种表有各种 count, 是把 count 提出来放到一个专门的 counter 表好呢,还是放在各自的表里好呢,一般是怎么处理的?

#5 楼 @fresh_fish 看结构啦。 比如 user has many topics 这种。user 表里有 topics_count. 还有一种是比如总帖子数量,总用户数量,网站总访问量等,这些需要单独表或 redis 记录。

#6 楼 @hooopo 谢谢。现在公司要求全丢到一个表里,相当纠结啊。。。。

#7 楼 @fresh_fish 为什么啊 DBA 要求的?

#8 楼 @hooopo 是公司一个比较资深的程序员定的,说是有这样的场景,比如 拿 user 表说:有时仅仅是需要更新一下 count 数据,如用户的 blogs_count, photos_count 等,和 user 本身 并没多大关系,却要去更新一下 user 表,不太好也不太保险,要保证即使更新 count 出错,user 也能正常访问,大概是这么说的。

#9 楼 @fresh_fish 这有啥不保险的,数据库就是拿来干这活的...

#8 楼 @hooopo 还有就是 有时可能仅需要取 count 数据,却要顺带取出庞大的 user 数据,但是貌似现在想不到这样的场景

#11 楼 @fresh_fish 可以指定字段的。。。select topics_count from users

@hooopo 想到一个问题,有的时候做表表,我们需要统计一天的增长量,Order.group("date(purchased_at)").select("purchased_at, sum(total_price) as total_price"), 这样的话每次报表现实的时候都要查询,这种时候有没有好的解决方法呢

很赞啊,非常实用

例子可以改成 user_name 更加贴切

#13 楼 @lxyluu 可以每天生成一条记录,记录增长量,也是 counter cache 的思路。 插入订单的时候给当天的记录 +1,查询的时候一条简单 select 语句搞定。 其他类型的统计也类似。

匿名 #17 2012年07月17日

额。。。不知道你这个例子。。。状态用来冗余会比较蛋疼,如果以状态为场景,应该很多地方都会出现,这个。。。真的不太好。不过工具挺好。

#15 楼 @huacnlee 如果是 user_name 这种我不推荐做冗余,可以通过对象缓存的方式解决。我举那个例子是不能通过对象缓存方式解决的。其实很贴切。

user 对象一般都会在缓存里,取 name 不需要查数据库,当然冗余了更快。。 类似的讨论可以看这个帖子:http://www.iteye.com/topic/451660#1166006

#17 楼 @help5305fff 冗余什么由开发者根据场景自己决定,我只是真的见过需要冗余状态的场景。。才顺手写了这个例子:-)

需要 登录 后方可回复, 如果你还没有账号请 注册新账号