tags的数据库设计问题

2012-12-08 22:58:42 +08:00
 talentsnail
每个topic有几个tags,每个tag也能对应多个topic,应该如何设计数据库最合理呢?

想到的一种解决办法是三张表:
1.topic (topic_id,tags)多个tags用某个特殊符号分隔
2.tag (tag_id,tag)
3.topic_tag (topic_id,tag_id)

但是觉得效率会很低,大家的解决方案是怎样?
6649 次点击
所在节点    MySQL
50 条回复
huaxinjiayou
2012-12-10 10:35:06 +08:00
跟楼主一样…多对多…坐等更好的解决方案…
ipconfiger
2012-12-10 14:24:45 +08:00
符号分隔做冗余的方案基本上多此一举,如果要用性能来说事的话,加缓存即可,何必在查询的时候冗余到字段里,这样在添加新TAG的时候又要做不少事情来保持冗余数据的同步。正确的使用缓存的方法是缓存计算的结果非计算的中间步骤。冗余字段的方式就是典型的舍本逐末了。
假设一个场景,读取topic,同时读取topic相关的TAG,那么你应该缓存的是
select * from topic where id=id 和 select * from topic_tag where topic_id=id 的返回结果,甚至是这个页面渲染的结果,到时候直接输出页面就行了,序列化成字符串存储在一个列里的话,如果不缓存select * from topic where id=id 的结果,那么每次查询都有开销,而且这个方式还会增大每次查询的返回数据大小。如果缓存了整个逻辑的结果那么你冗余存的这一次就没什么意义,反而增大了数据库的冗余,还存在不同步的风险。所以什么都好分割啊,什么存json啊都是异端的设计,基本上都是没有经受过大负载访问洗礼的幼稚设计方法。
wuxqing
2012-12-10 14:43:46 +08:00
@ipconfiger
使用缓存,也要考虑同步的风险
napoleonu
2012-12-10 14:55:05 +08:00
@ipconfiger

stackoverflow.com Alexa Traffic Rank: 85 Traffic Rank in IN: 28

我保证stackoverflow用这种设计都不会出问题。

亲,你生下来就是为了做淘宝的吧,哪那么多大网站啊。
napoleonu
2012-12-10 14:57:14 +08:00
@napoleonu 如果一个页面50条记录,我还真不信每个页面访问50次cache的代价比把tag冗余一下的代价要低。
ipconfiger
2012-12-10 15:55:57 +08:00
@wuxqing 用缓存肯定要实现针对资源的notification机制,当版本过期就应该让缓存失效重新加载数据就行了。

@napoleonu 亲,你理解错了吧,如果只是tag数量,这个存字段里是ok的,但是TAG本身存字段里确实不科学。另外你估计还是没有理解缓存结果而不是运算中间过程的意义是啥
napoleonu
2012-12-10 17:02:44 +08:00
@ipconfiger

http://tagging.pui.ch/post/37027746608/tagsystems-performance-tests

多年前看到的一篇文章,使用这种设计的多着呢。

我确实没理解你“缓存结果”的做法,stackoverflow一共400万帖,按照50条每页(每条平均3个tag),分80000页,之后,每增加一条记录就重新生成80000页的缓存?不同的页面或者排序可能还有不同的分页,请不吝赐教。

可能我对你只有仰望的份,但你说我“幼稚”,我只能回敬你一句“二逼”,请原谅我的小心眼。
napoleonu
2012-12-10 17:05:27 +08:00
@napoleonu 因为我跟你不熟。
bhuztez
2012-12-10 18:37:30 +08:00
搭车求问,PostgreSQL intarray怎么建索引才对啊?我自己试的时候,发现无论建GIN还是GiST索引,EXPLAIN的结果都和没建没区别啊

http://www.postgresql.org/docs/current/static/intarray.html
zhfsxtx
2012-12-10 21:53:38 +08:00
那如果 是 mongodb 应该怎么保存呢
ipconfiger
2012-12-12 09:36:12 +08:00
@napoleonu 既然这么不客气那我就来指出你的二逼之处。你所谓的重新生成80000页的缓存的说法极其可笑,很显然你没用过缓存,而且把缓存和生成静态页弄混了。回去多学几年吧,我没有必要在这里教你缓存怎么用。二逼青年
ElmerZhang
2012-12-12 10:14:27 +08:00
楼上那些把tag或者tagid拼成各种字符串写在一个字段里的,八成是根本没考虑由tag查topic这种常用场景。
把tag或tagid拼成一个字符串记一起,怎么查?用like?查一次就全表扫描一次,机器表示压力很大。
yupbank
2012-12-12 10:21:43 +08:00
@napoleonu ...那个topic-> tag还是加个缓存吧,不要放表了,不然一个topic新增一个tag,你多了一张topic表需要维护。

80000页的缓存问题。。哥,缓存真不是这么操作的,一口气命中80000页也太流弊了。。
yupbank
2012-12-12 10:23:38 +08:00
@ElmerZhang 。。。人家有topic_tag表

其实扯那么多范式也没有说到点子吧,楼主是来问他那个冗余巧不巧妙的。
ElmerZhang
2012-12-12 13:38:45 +08:00
@yupbank 我是在说楼上有些不要 topic_tag 表的。我认为楼主的设计是标准答案。
xjay
2012-12-12 14:52:05 +08:00
1.尽量避免join
2.可以把tagids以及tagnames一起存放进topic表内
3.你的设计表结构还是可以不变
huxos
2012-12-12 23:34:37 +08:00
为什么我觉得这样简单点呢 topic 表什么都不变。
tags(topic_id, tag_value);
每一个topic 有一个tag 就向tags 插一条。
还通过tag_value 轻松的得到一个topic 的列表。
napoleonu
2012-12-12 23:34:52 +08:00
@ipconfiger 我只是想告诉你你可以缓存page,缓存list的代价很大。恩,还没毕业,等我工作两年应该就懂了吧。
napoleonu
2012-12-12 23:39:54 +08:00
@yupbank 网站型的应用读多写少,适量增加写的复杂度来改善读的压力很正常。另外一种比较常见的牺牲写来提高读的案例就是基数,总数计数,分类计数,等等各种计数,看起来写的时候要维护这些似乎很麻烦,但是一次写可以为N次读提供方便。


@ipconfiger 二逼,我说你二逼是因为你不礼貌,我说了技术上我对你只有仰望。已BLOCK,二逼。
napoleonu
2012-12-12 23:47:50 +08:00
@ElmerZhang 用户通过某条post的tag查找这一tag的所有信息流程可以这样

通过tag获得tagid(tagid_tag表)

通过tagid获得这一tag的所有post (tagid_postid表)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/54442

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX