0

Web 应用程序将为用户提供来自不同类别的不同帖子。
例如类别可能是“幽默”、“运动”等。

所以为此我将有一个简单的表: Categories(id, category_name)

我想跟踪用户访问特定类别的次数,因此下次用户登录时,他的默认页面将是用户访问次数最多的两个不同类别的帖子页面。

基本思想(我将使用 Ruby on Rails),在控制器提供某个页面之前,该类别的计数器将递增并保存到 DB 中。 我的问题是我不知道在哪里保存这个类别的计数器?

第一个想法(表计数器):

Counters(id, category_name1, category_name2, ..., category_nameN, user_id)

其中 category_name 是整数字段,表示用户访问次数(特定类别)。这个想法不好,因为当我添加新类别时,我必须更改此表以添加新列。

第二个想法:

Counters(id, count, category_id, user_id)

对我来说更好的主意但我猜仍然不是很好的性能,因为每个用户我将有 N 行,其中 N 是类别数。那么,如果我有 1000 个用户和 10 个类别,那将是过度杀戮?

4

2 回答 2

1

使用第二种方法。1000 个用户 * 10 个类别 = 10000 行,这在数据库世界中绝不被视为“大”。

除非您的客户端库强迫您,否则您应该使用自然键设计:

Counter(user_id, category_id, count, PRIMARY KEY (user_id, category_id))

如果您的 DBMS 支持集群,则整个表可以在物理上表示为单个 B-Tree,这样可以高效地查询、修改和缓存。

That being said, are you sure you need the count for eternity? Perhaps it would be better to keep the count only for the last 30 days1? That would require: 1000 users * 10 categories * 30 days = 300000 rows, which is still not particularly "large".

Alternatively, you might run a periodic batch job that multiplies all counts by some factor less than 1 (say 0.9), which would make old visits less "important" than the new ones. You'd probably want to use some floating-point type (as opposed to integer) for the counter in that scenario.


1 Or 90 or whatever...

于 2013-10-30T22:14:05.927 回答
1

For that volume I would use the second approach -

Counters(id, count, category_id, user_id)

unless you encounter performance issues and only then switch to the other approach.

You can also use a counter-cache to help with this:

http://guides.rubyonrails.org/association_basics.html#detailed-association-reference

e.g.

class Counter < ActiveRecord::Base
  belongs_to :category, dependent: :destroy,
    counter_cache: true
end

As always with Rails it's best to start on the rails before going off them.

于 2013-10-30T22:21:14.457 回答