有效地存储一堆外键(Serialize vs New Table)

时间:2012-01-17 20:38:16

标签: mysql sql mysqli

我需要保留已查看一段内容的user_id列表,以计算唯一的用户视图。 user_idINT(10)字段。

我可以使用user_idcontent_idviewed创建一个表,并在每次用户查看内容时添加一行,但这似乎很慢。对于用户查看的每个内容,我将不得不查询类似

的内容

SELECT COUNT(*) FROM viewed_table WHERE content_id = $content_id;

获取观看量,然后

SELECT COUNT(*) FROM viewed_table WHERE user_id = $user_id AND content_id = $content_id;

查看用户是否已查看此内容,如果没有,则插入一行。 (每次用户查看某些内容时,会有2到3个额外的查询)。

或...

每次添加viewed时,我应该在内容表中添加unserialize()字段吗?serialize() / user_id数组? json_encode()是另一个类似的选项,在大型数据集上似乎更快。

对于不断增长的网站,哪个选项最快/最具扩展性?谢谢你的帮助!

3 个答案:

答案 0 :(得分:2)

拇指规则:通常序列化关系数据,特别是外键==高速公路到地狱。

有一个表格,您可以存储所有视图的总和,并且只增加/减少它。这应该比SELECT COUNT(*) FROM viewed_table WHERE content_id = $content_id;

更快

查看给定用户是否已查看指定页面SELECT 1 FROM viewed_table WHERE user_id = $user_id AND content_id = $content_id LIMIT 1;。这将返回0或1行,因此您只需要检查它。

答案 1 :(得分:1)

你可以这样做:

viewed_table
----------------------------
user_id int(10)
content_id int(10)
primary key (user_id, content_id)

要插入记录:

INSERT IGNORE INTO viewed_table (user_id, content_id) VALUES ($user_id, $content_id)

您的affected_rows计数将显示这是否是新行(用户尚未查看内容)。没有选择那个。

如果您希望实现总计表,这也是您为所选content_id添加一个总计的点。

viewed_table_totals
----------------------------
content_id int(10)
view_count int(10)
primary key (content_id)

更新行:

INSERT INTO viewed_table_totals (content_id, view_count) VALUES($content_id, 1)
  ON DUPLICATE KEY UPDATE view_count = view_count + 1

由于您需要进行唯一身份访问,因此无法避免存储每次用户访问。

答案 2 :(得分:0)

毫无疑问是第一种选择。

每次想要计算视图数量时,或者每当有人阅读文章时序列化/反序列化id列表的成本都会比编入良好索引的第二个表上的COUNTing慢几个数量级。

您可以通过将计数存储在内存中(使用Memcached或Redis之类的东西),或者将view_count列添加到内容表中,并在添加到Viewed_table时只增加该数字,从而进一步改善这一点。