2

如果它现在很重要,我正在使用 MySQL/MyISAM,但我愿意使用 PostgreSQL。我也愿意使用 memcached。

考虑一个用于存储论坛主题的表:

id forum_name post_date
1  Hey!       2009-01-01 12:00:00
  • 存储与线程相关的实体(例如投票、视图和计数器)的最佳实践是什么?

我是不是该..

创建一个单独的表,例如

id thread_id views
1  1         532

还是将其保留为初始线程表中的一列?

id forum_name post_date              views
1  Hey!       2009-01-01 12:00:00    532

另一个相关的花絮,显示和增加页面浏览量的实用解决方案是什么?我读了这个帖子,似乎我可以只缓存一个值一段时间,我对递增部分并不完全清楚 - 也许就像将值存储在某个地方的平面文件中,然后定期使用 cronjobs 更新数据库论坛视图每隔一小时左右?

编辑: 澄清一下,投票就像每个线程一票一样,并且可能会发生逆转。别管我说的计数器是什么意思。

4

2 回答 2

8

表决

我建议在线程表之外定义两个表 -VOTE_CODESTHREAD_VOTES. 乍一看,它可能看起来过度标准化,但该格式允许您更改投票值,而无需进行重大的 DML 更改。

VOTE_CODES桌子

  • vote_code, 主键, IE: up, down
  • vote_cast_value--value 归因于赞成/反对票
  • vote_caster_value--可选,如果你想保持 SO 的负面投票风格影响施法者。

THREAD_VOTES桌子

  • thread_id
  • user_id
  • vote_code

中的所有列THREAD_VOTES都是主键 - 这将确保给定用户和线程的行数与投票代码一样多。假设只有两个代码,这将支持撤销投票的能力,因为只能有两条记录 - 一条带有任一代码。

意见

我建议存储:

  • 线程 ID
  • IP地址
  • user_agent --粗略的浏览器捕获
  • 时间戳

以上都是主键。您的表格将快速填充,但它使您能够在视图中创建计算列以获得更准确的报告。

于 2009-12-22T03:58:19.400 回答
1

平面文件显然是个坏主意,因为您需要实现锁定(数据库已经这样做了,并且该代码中的错误更少)。

关系数据库设计更像是一门艺术而不是一门科学:你可以拥有

CREATE TABLE threads (
  tid THREADID
, title THREADTITLE
, views COUNTER
, PRIMARY KEY (tid)
);

它不会比“正确”更多也不会更少

CREATE TABLE threads (
  tid THREADID
, title THREADTITLE
, PRIMARY KEY (tid)
);

CREATE TABLE views (
  tid THREADID
, views COUNTER
, PRIMARY KEY (tid)
, FOREIGN KEY (tid)
  REFERENCES threads
);

所以这真的取决于你。

我想说:先做最简单的事情,如果你觉得有必要(例如出于性能原因),让它变得更复杂。IOW:将views COUNTER属性放入threads. 如果事实证明流量正在损害性能(属性上的太多更新threads.views意味着 dbms 必须在其他属性中重新调整其他不可变数据),您总是可以将表一分为二,并用连接它们的视图替换它. 瞧,不可变(或很少更改)的数据与易失性数据分开,界面保持不变。

当然,使用 PostgreSQL。上面显示的代码在该 dbms 中有效,只需添加以下代码:

CREATE DOMAIN threadid
AS INT NOT NULL;

CREATE DOMAIN threadtitle
AS TEXT NOT NULL
CHECK (LENGTH(VALUE) > 0);

CREATE DOMAIN counter
AS INT NOT NULL
CHECK (VALUE > 0);

编辑以驳斥 OMG Ponies 的评论:当然是安全的。

UPDATE threads SET
  views = views + 1
WHERE tid = X

要么成功,要么退出。

编辑 2以增加对投票方面的考虑

假设规范是:用户可以对线程投赞成票(+1)或反对票(-1),他或她对给定线程的投票总和不得超过|1|,并且历史是无关紧要的。iow 用户可以对线程投赞成票,然后投反对票以将其投票重置为“不投票”,然后再次投反对票以“投反对票”,等等。

CREATE DOMAIN vote
AS INT NOT NULL
CHECK (VALUE BETWEEN -1 AND 1);

CREATE TABLE votes (
  tid THREADID
, uid USERID
, vote VOTE
, PRIMARY KEY (tid, uid)
);

在 MySQL 中,你可以

INSERT INTO votes (
  tid
, uid
, vote
) VALUES (
  X
, Y
, Z -- +1 or -1
)
ON DUPLICATE KEY UPDATE
vote = vote + Z

唉,PostgreSQL(还)没有内置这样的功能,所以你需要使用惯用的用户级实现

于 2009-12-22T04:27:34.643 回答